From 6687faf49fb9db4cc1fc4734223ab3df0bff69a2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 10 May 2017 11:40:52 +0300 Subject: [PATCH 001/414] Release 1.13.0-1 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 02587ed..a36a3df 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,9 @@ -nginx (1.13.0-1) UNRELEASED; urgency=medium +nginx (1.13.0-1) experimental; urgency=medium * New upstream release. We now target nginx mainline (1.13.x). - -- Christos Trochalakis Fri, 05 May 2017 13:01:30 +0300 + -- Christos Trochalakis Wed, 10 May 2017 11:40:38 +0300 nginx (1.12.0-1) experimental; urgency=medium From 501f9c7a40edb258c26f588443acf395ab89e7e8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 May 2017 11:40:55 +0300 Subject: [PATCH 002/414] New upstream version 1.13.1 --- CHANGES | 30 + CHANGES.ru | 29 + auto/cc/conf | 36 +- auto/cc/sunc | 5 +- auto/os/linux | 14 - auto/unix | 12 + contrib/vim/syntax/nginx.vim | 3434 ++++++++++---------- src/core/nginx.h | 4 +- src/core/ngx_connection.c | 43 + src/core/ngx_connection.h | 1 + src/core/ngx_murmurhash.c | 2 + src/event/ngx_event_accept.c | 2 +- src/event/ngx_event_openssl.c | 2 +- src/http/modules/ngx_http_access_module.c | 22 +- src/http/modules/ngx_http_fastcgi_module.c | 3 + src/http/modules/ngx_http_proxy_module.c | 1 + src/http/modules/ngx_http_realip_module.c | 83 +- src/http/modules/ngx_http_scgi_module.c | 1 + src/http/modules/ngx_http_uwsgi_module.c | 1 + src/http/ngx_http_core_module.c | 35 +- src/http/ngx_http_file_cache.c | 57 +- src/http/ngx_http_header_filter_module.c | 2 +- src/http/ngx_http_parse.c | 15 +- src/http/ngx_http_request.c | 99 +- src/http/ngx_http_request.h | 9 +- src/http/ngx_http_special_response.c | 10 +- src/http/ngx_http_upstream.c | 98 +- src/http/v2/ngx_http_v2.c | 25 +- src/http/v2/ngx_http_v2_filter_module.c | 4 +- src/mail/ngx_mail_handler.c | 2 +- src/os/unix/ngx_process.c | 1 + src/stream/ngx_stream_access_module.c | 22 +- src/stream/ngx_stream_core_module.c | 19 +- src/stream/ngx_stream_proxy_module.c | 19 +- src/stream/ngx_stream_realip_module.c | 83 +- src/stream/ngx_stream_ssl_module.c | 15 +- 36 files changed, 2225 insertions(+), 2015 deletions(-) diff --git a/CHANGES b/CHANGES index 9aa8c03..992cc70 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,34 @@ +Changes with nginx 1.13.1 30 May 2017 + + *) Feature: now a hostname can be used as the "set_real_ip_from" + directive parameter. + + *) Feature: vim syntax highlighting scripts improvements. + + *) Feature: the "worker_cpu_affinity" directive now works on DragonFly + BSD. + Thanks to Sepherosa Ziehau. + + *) Bugfix: SSL renegotiation on backend connections did not work when + using OpenSSL before 1.1.0. + + *) Workaround: nginx could not be built with Oracle Developer Studio + 12.5. + + *) Workaround: now cache manager ignores long locked cache entries when + cleaning cache based on the "max_size" parameter. + + *) Bugfix: client SSL connections were immediately closed if deferred + accept and the "proxy_protocol" parameter of the "listen" directive + were used. + + *) Bugfix: in the "proxy_cache_background_update" directive. + + *) Workaround: now the "tcp_nodelay" directive sets the TCP_NODELAY + option before an SSL handshake. + + Changes with nginx 1.13.0 25 Apr 2017 *) Change: SSL renegotiation is now allowed on backend connections. diff --git a/CHANGES.ru b/CHANGES.ru index 0e2d1aa..d42b90f 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,33 @@ +Изменения в nginx 1.13.1 30.05.2017 + + *) Добавление: теперь в качестве параметра директивы set_real_ip_from + можно указывать имя хоста. + + *) Добавление: улучшения в скриптах подсветки синтаксиса для vim. + + *) Добавление: директива worker_cpu_affinity теперь работает на + DragonFly BSD. + Спасибо Sepherosa Ziehau. + + *) Исправление: SSL renegotiation в соединениях к бэкендам не работал + при использовании OpenSSL до 1.1.0. + + *) Изменение: nginx не собирался с Oracle Developer Studio 12.5. + + *) Изменение: теперь cache manager пропускает заблокированные записи при + очистке кэша по max_size. + + *) Исправление: клиентские SSL-соединения сразу закрывались, если + использовался отложенный accept и параметр proxy_protocol директивы + listen. + + *) Исправление: в директиве proxy_cache_background_update. + + *) Изменение: теперь директива tcp_nodelay устанавливает опцию + TCP_NODELAY перед SSL handshake. + + Изменения в nginx 1.13.0 25.04.2017 *) Изменение: теперь SSL renegotiation допускается в соединениях к diff --git a/auto/cc/conf b/auto/cc/conf index b3b9f92..afbca62 100644 --- a/auto/cc/conf +++ b/auto/cc/conf @@ -178,21 +178,25 @@ if [ "$NGX_PLATFORM" != win32 ]; then fi - ngx_feature="gcc builtin atomic operations" - ngx_feature_name=NGX_HAVE_GCC_ATOMIC - ngx_feature_run=yes - ngx_feature_incs= - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test="long n = 0; - if (!__sync_bool_compare_and_swap(&n, 0, 1)) - return 1; - if (__sync_fetch_and_add(&n, 1) != 1) - return 1; - if (n != 2) - return 1; - __sync_synchronize();" - . auto/feature + if [ "$NGX_CC_NAME" = "sunc" ]; then + echo "checking for gcc builtin atomic operations ... disabled" + else + ngx_feature="gcc builtin atomic operations" + ngx_feature_name=NGX_HAVE_GCC_ATOMIC + ngx_feature_run=yes + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="long n = 0; + if (!__sync_bool_compare_and_swap(&n, 0, 1)) + return 1; + if (__sync_fetch_and_add(&n, 1) != 1) + return 1; + if (n != 2) + return 1; + __sync_synchronize();" + . auto/feature + fi if [ "$NGX_CC_NAME" = "ccc" ]; then @@ -209,7 +213,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then var(0, buf, \"%d\", 1); if (buf[0] != '1') return 1" . auto/feature - fi + fi ngx_feature="gcc variadic macros" diff --git a/auto/cc/sunc b/auto/cc/sunc index 806ccc4..552c2d3 100644 --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -8,7 +8,10 @@ # Sun C 5.9 SunOS_i386 2007/05/03 Sun Studio 12 # Sun C 5.9 SunOS_sparc 2007/05/03 # Sun C 5.10 SunOS_i386 2009/06/03 Sun Studio 12.1 -# Sun C 5.11 SunOS_i386 2010/08/13 Sun Studio 12.2 +# Sun C 5.11 SunOS_i386 2010/08/13 Oracle Solaris Studio 12.2 +# Sun C 5.12 SunOS_i386 2011/11/16 Oracle Solaris Studio 12.3 +# Sun C 5.13 SunOS_i386 2014/10/20 Oracle Solaris Studio 12.4 +# Sun C 5.14 SunOS_i386 2016/05/31 Oracle Developer Studio 12.5 NGX_SUNC_VER=`$CC -V 2>&1 | grep 'Sun C' 2>&1 \ | sed -e 's/^.* Sun C \(.*\)/\1/'` diff --git a/auto/os/linux b/auto/os/linux index fae8842..a0c8795 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -157,20 +157,6 @@ ngx_feature_test="if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) return 1" . auto/feature -# sched_setaffinity() - -ngx_feature="sched_setaffinity()" -ngx_feature_name="NGX_HAVE_SCHED_SETAFFINITY" -ngx_feature_run=no -ngx_feature_incs="#include " -ngx_feature_path= -ngx_feature_libs= -ngx_feature_test="cpu_set_t mask; - CPU_ZERO(&mask); - sched_setaffinity(0, sizeof(cpu_set_t), &mask)" -. auto/feature - - # crypt_r() ngx_feature="crypt_r()" diff --git a/auto/unix b/auto/unix index 52060fc..7c6a855 100644 --- a/auto/unix +++ b/auto/unix @@ -300,6 +300,18 @@ if [ $ngx_found = no ]; then fi +ngx_feature="sched_setaffinity()" +ngx_feature_name="NGX_HAVE_SCHED_SETAFFINITY" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="cpu_set_t mask; + CPU_ZERO(&mask); + sched_setaffinity(0, sizeof(cpu_set_t), &mask)" +. auto/feature + + ngx_feature="SO_SETFIB" ngx_feature_name="NGX_HAVE_SETFIB" ngx_feature_run=no diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index a52891b..dc8c0cb 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -5,2115 +5,2145 @@ if exists("b:current_syntax") finish end -setlocal iskeyword+=. -setlocal iskeyword+=/ -setlocal iskeyword+=: +" general syntax -syn match ngxVariable '\$\(\w\+\|{\w\+}\)' -syn match ngxVariableBlock '\$\(\w\+\|{\w\+}\)' contained +if has("patch-7.4.1142") + " except control characters, ";", "{", and "}" + syn iskeyword 33-58,60-122,124,126-255 +endif + +syn match ngxName '\([^;{} \t\\]\|\\.\)\+' + \ contains=@ngxDirectives + \ nextgroup=@ngxParams skipwhite skipempty +syn match ngxParam '\([^;{ \t\\]\|\\.\)\+' + \ contained + \ contains=ngxVariable + \ nextgroup=@ngxParams skipwhite skipempty +syn region ngxString start=+\z(["']\)+ end=+\z1+ skip=+\\\\\|\\\z1+ + \ contains=ngxVariableString + \ nextgroup=@ngxParams skipwhite skipempty +syn match ngxParamComment '#.*$' + \ nextgroup=@ngxParams skipwhite skipempty +syn match ngxSemicolon ';' contained +syn region ngxBlock start=+{+ end=+}+ contained + \ contains=@ngxTopLevel +syn match ngxComment '#.*$' + +syn match ngxVariable '\$\w\+' contained syn match ngxVariableString '\$\(\w\+\|{\w\+}\)' contained -syn region ngxBlock start=+^+ end=+{+ skip=+\${+ contains=ngxComment,ngxDirectiveBlock,ngxVariableBlock,ngxString oneline -syn region ngxString start=+[^:a-zA-Z>!\\@]\z(["']\)+lc=1 end=+\z1+ skip=+\\\\\|\\\z1+ contains=ngxVariableString -syn match ngxComment ' *#.*$' -syn keyword ngxBoolean on -syn keyword ngxBoolean off +syn cluster ngxTopLevel + \ contains=ngxName,ngxString,ngxComment +syn cluster ngxDirectives + \ contains=ngxDirective,ngxDirectiveBlock,ngxDirectiveImportant + \ add=ngxDirectiveControl,ngxDirectiveError,ngxDirectiveDeprecated + \ add=ngxDirectiveThirdParty +syn cluster ngxParams + \ contains=ngxParam,ngxString,ngxParamComment,ngxSemicolon,ngxBlock -syn keyword ngxDirectiveBlock http contained -syn keyword ngxDirectiveBlock mail contained -syn keyword ngxDirectiveBlock events contained -syn keyword ngxDirectiveBlock server contained -syn keyword ngxDirectiveBlock types contained -syn keyword ngxDirectiveBlock location contained -syn keyword ngxDirectiveBlock upstream contained -syn keyword ngxDirectiveBlock charset_map contained -syn keyword ngxDirectiveBlock limit_except contained -syn keyword ngxDirectiveBlock if contained -syn keyword ngxDirectiveBlock geo contained -syn keyword ngxDirectiveBlock map contained -syn keyword ngxDirectiveBlock split_clients contained +" boolean parameters -syn keyword ngxDirectiveImportant include -syn keyword ngxDirectiveImportant root -syn keyword ngxDirectiveImportant server -syn keyword ngxDirectiveImportant server_name -syn keyword ngxDirectiveImportant listen contained -syn region ngxDirectiveImportantListen matchgroup=ngxDirectiveImportant start=+listen+ skip=+\\\\\|\\\;+ end=+;+he=e-1 contains=ngxListenOptions,ngxString -syn keyword ngxDirectiveImportant internal -syn keyword ngxDirectiveImportant proxy_pass -syn keyword ngxDirectiveImportant memcached_pass -syn keyword ngxDirectiveImportant fastcgi_pass -syn keyword ngxDirectiveImportant scgi_pass -syn keyword ngxDirectiveImportant uwsgi_pass -syn keyword ngxDirectiveImportant try_files +syn keyword ngxBoolean contained on off + \ nextgroup=@ngxParams skipwhite skipempty +syn cluster ngxParams add=ngxBoolean -syn keyword ngxListenOptions default_server contained -syn keyword ngxListenOptions ssl contained -syn keyword ngxListenOptions http2 contained -syn keyword ngxListenOptions spdy contained -syn keyword ngxListenOptions proxy_protocol contained -syn keyword ngxListenOptions setfib contained -syn keyword ngxListenOptions fastopen contained -syn keyword ngxListenOptions backlog contained -syn keyword ngxListenOptions rcvbuf contained -syn keyword ngxListenOptions sndbuf contained -syn keyword ngxListenOptions accept_filter contained -syn keyword ngxListenOptions deferred contained -syn keyword ngxListenOptions bind contained -syn keyword ngxListenOptions ipv6only contained -syn keyword ngxListenOptions reuseport contained -syn keyword ngxListenOptions so_keepalive contained -syn keyword ngxListenOptions keepidle contained +" listen directive -syn keyword ngxDirectiveControl break -syn keyword ngxDirectiveControl return -syn keyword ngxDirectiveControl rewrite -syn keyword ngxDirectiveControl set +syn cluster ngxTopLevel add=ngxDirectiveListen +syn keyword ngxDirectiveListen listen + \ nextgroup=@ngxListenParams skipwhite skipempty +syn match ngxListenParam '\([^;{ \t\\]\|\\.\)\+' + \ contained + \ nextgroup=@ngxListenParams skipwhite skipempty +syn region ngxListenString start=+\z(["']\)+ end=+\z1+ skip=+\\\\\|\\\z1+ + \ contained + \ nextgroup=@ngxListenParams skipwhite skipempty +syn match ngxListenComment '#.*$' + \ contained + \ nextgroup=@ngxListenParams skipwhite skipempty +syn keyword ngxListenOptions contained + \ default_server ssl http2 spdy proxy_protocol + \ setfib fastopen backlog rcvbuf sndbuf accept_filter deferred bind + \ ipv6only reuseport so_keepalive keepidle + \ nextgroup=@ngxListenParams skipwhite skipempty +syn cluster ngxListenParams + \ contains=ngxListenParam,ngxListenString,ngxListenComment + \ add=ngxListenOptions -syn keyword ngxDirectiveError error_page -syn keyword ngxDirectiveError post_action +syn keyword ngxDirectiveBlock contained http +syn keyword ngxDirectiveBlock contained mail +syn keyword ngxDirectiveBlock contained events +syn keyword ngxDirectiveBlock contained server +syn keyword ngxDirectiveBlock contained types +syn keyword ngxDirectiveBlock contained location +syn keyword ngxDirectiveBlock contained upstream +syn keyword ngxDirectiveBlock contained charset_map +syn keyword ngxDirectiveBlock contained limit_except +syn keyword ngxDirectiveBlock contained if +syn keyword ngxDirectiveBlock contained geo +syn keyword ngxDirectiveBlock contained map +syn keyword ngxDirectiveBlock contained split_clients -syn keyword ngxDirectiveDeprecated connections -syn keyword ngxDirectiveDeprecated imap -syn keyword ngxDirectiveDeprecated limit_zone -syn keyword ngxDirectiveDeprecated mysql_test -syn keyword ngxDirectiveDeprecated open_file_cache_retest -syn keyword ngxDirectiveDeprecated optimize_server_names -syn keyword ngxDirectiveDeprecated satisfy_any -syn keyword ngxDirectiveDeprecated so_keepalive +syn keyword ngxDirectiveImportant contained include +syn keyword ngxDirectiveImportant contained root +"syn keyword ngxDirectiveImportant contained server +syn keyword ngxDirectiveImportant contained server_name +"syn keyword ngxDirectiveImportant contained listen +syn keyword ngxDirectiveImportant contained internal +syn keyword ngxDirectiveImportant contained proxy_pass +syn keyword ngxDirectiveImportant contained memcached_pass +syn keyword ngxDirectiveImportant contained fastcgi_pass +syn keyword ngxDirectiveImportant contained scgi_pass +syn keyword ngxDirectiveImportant contained uwsgi_pass +syn keyword ngxDirectiveImportant contained try_files -syn keyword ngxDirective absolute_redirect -syn keyword ngxDirective accept_mutex -syn keyword ngxDirective accept_mutex_delay -syn keyword ngxDirective acceptex_read -syn keyword ngxDirective access_log -syn keyword ngxDirective add_after_body -syn keyword ngxDirective add_before_body -syn keyword ngxDirective add_header -syn keyword ngxDirective addition_types -syn keyword ngxDirective aio -syn keyword ngxDirective aio_write -syn keyword ngxDirective alias -syn keyword ngxDirective allow -syn keyword ngxDirective ancient_browser -syn keyword ngxDirective ancient_browser_value -syn keyword ngxDirective auth_basic -syn keyword ngxDirective auth_basic_user_file -syn keyword ngxDirective auth_http -syn keyword ngxDirective auth_http_header -syn keyword ngxDirective auth_http_pass_client_cert -syn keyword ngxDirective auth_http_timeout -syn keyword ngxDirective auth_jwt -syn keyword ngxDirective auth_jwt_key_file -syn keyword ngxDirective auth_request -syn keyword ngxDirective auth_request_set -syn keyword ngxDirective autoindex -syn keyword ngxDirective autoindex_exact_size -syn keyword ngxDirective autoindex_format -syn keyword ngxDirective autoindex_localtime -syn keyword ngxDirective charset -syn keyword ngxDirective charset_map -syn keyword ngxDirective charset_types -syn keyword ngxDirective chunked_transfer_encoding -syn keyword ngxDirective client_body_buffer_size -syn keyword ngxDirective client_body_in_file_only -syn keyword ngxDirective client_body_in_single_buffer -syn keyword ngxDirective client_body_temp_path -syn keyword ngxDirective client_body_timeout -syn keyword ngxDirective client_header_buffer_size -syn keyword ngxDirective client_header_timeout -syn keyword ngxDirective client_max_body_size -syn keyword ngxDirective connection_pool_size -syn keyword ngxDirective create_full_put_path -syn keyword ngxDirective daemon -syn keyword ngxDirective dav_access -syn keyword ngxDirective dav_methods -syn keyword ngxDirective debug_connection -syn keyword ngxDirective debug_points -syn keyword ngxDirective default_type -syn keyword ngxDirective degradation -syn keyword ngxDirective degrade -syn keyword ngxDirective deny -syn keyword ngxDirective devpoll_changes -syn keyword ngxDirective devpoll_events -syn keyword ngxDirective directio -syn keyword ngxDirective directio_alignment -syn keyword ngxDirective disable_symlinks -syn keyword ngxDirective empty_gif -syn keyword ngxDirective env -syn keyword ngxDirective epoll_events -syn keyword ngxDirective error_log -syn keyword ngxDirective etag -syn keyword ngxDirective eventport_events -syn keyword ngxDirective expires -syn keyword ngxDirective f4f -syn keyword ngxDirective f4f_buffer_size -syn keyword ngxDirective fastcgi_bind -syn keyword ngxDirective fastcgi_buffer_size -syn keyword ngxDirective fastcgi_buffering -syn keyword ngxDirective fastcgi_buffers -syn keyword ngxDirective fastcgi_busy_buffers_size -syn keyword ngxDirective fastcgi_cache -syn keyword ngxDirective fastcgi_cache_bypass -syn keyword ngxDirective fastcgi_cache_key -syn keyword ngxDirective fastcgi_cache_lock -syn keyword ngxDirective fastcgi_cache_lock_age -syn keyword ngxDirective fastcgi_cache_lock_timeout -syn keyword ngxDirective fastcgi_cache_max_range_offset -syn keyword ngxDirective fastcgi_cache_methods -syn keyword ngxDirective fastcgi_cache_min_uses -syn keyword ngxDirective fastcgi_cache_path -syn keyword ngxDirective fastcgi_cache_purge -syn keyword ngxDirective fastcgi_cache_revalidate -syn keyword ngxDirective fastcgi_cache_use_stale -syn keyword ngxDirective fastcgi_cache_valid -syn keyword ngxDirective fastcgi_catch_stderr -syn keyword ngxDirective fastcgi_connect_timeout -syn keyword ngxDirective fastcgi_force_ranges -syn keyword ngxDirective fastcgi_hide_header -syn keyword ngxDirective fastcgi_ignore_client_abort -syn keyword ngxDirective fastcgi_ignore_headers -syn keyword ngxDirective fastcgi_index -syn keyword ngxDirective fastcgi_intercept_errors -syn keyword ngxDirective fastcgi_keep_conn -syn keyword ngxDirective fastcgi_limit_rate -syn keyword ngxDirective fastcgi_max_temp_file_size -syn keyword ngxDirective fastcgi_next_upstream -syn keyword ngxDirective fastcgi_next_upstream_timeout -syn keyword ngxDirective fastcgi_next_upstream_tries -syn keyword ngxDirective fastcgi_no_cache -syn keyword ngxDirective fastcgi_param -syn keyword ngxDirective fastcgi_pass_header -syn keyword ngxDirective fastcgi_pass_request_body -syn keyword ngxDirective fastcgi_pass_request_headers -syn keyword ngxDirective fastcgi_read_timeout -syn keyword ngxDirective fastcgi_request_buffering -syn keyword ngxDirective fastcgi_send_lowat -syn keyword ngxDirective fastcgi_send_timeout -syn keyword ngxDirective fastcgi_split_path_info -syn keyword ngxDirective fastcgi_store -syn keyword ngxDirective fastcgi_store_access -syn keyword ngxDirective fastcgi_temp_file_write_size -syn keyword ngxDirective fastcgi_temp_path -syn keyword ngxDirective flv -syn keyword ngxDirective geoip_city -syn keyword ngxDirective geoip_country -syn keyword ngxDirective geoip_org -syn keyword ngxDirective geoip_proxy -syn keyword ngxDirective geoip_proxy_recursive -syn keyword ngxDirective google_perftools_profiles -syn keyword ngxDirective gunzip -syn keyword ngxDirective gunzip_buffers -syn keyword ngxDirective gzip -syn keyword ngxDirective gzip_buffers -syn keyword ngxDirective gzip_comp_level -syn keyword ngxDirective gzip_disable -syn keyword ngxDirective gzip_hash -syn keyword ngxDirective gzip_http_version -syn keyword ngxDirective gzip_min_length -syn keyword ngxDirective gzip_no_buffer -syn keyword ngxDirective gzip_proxied -syn keyword ngxDirective gzip_static -syn keyword ngxDirective gzip_types -syn keyword ngxDirective gzip_vary -syn keyword ngxDirective gzip_window -syn keyword ngxDirective hash -syn keyword ngxDirective health_check -syn keyword ngxDirective health_check_timeout -syn keyword ngxDirective hls -syn keyword ngxDirective hls_buffers -syn keyword ngxDirective hls_forward_args -syn keyword ngxDirective hls_fragment -syn keyword ngxDirective hls_mp4_buffer_size -syn keyword ngxDirective hls_mp4_max_buffer_size -syn keyword ngxDirective http2_chunk_size -syn keyword ngxDirective http2_body_preread_size -syn keyword ngxDirective http2_idle_timeout -syn keyword ngxDirective http2_max_concurrent_streams -syn keyword ngxDirective http2_max_field_size -syn keyword ngxDirective http2_max_header_size -syn keyword ngxDirective http2_max_requests -syn keyword ngxDirective http2_recv_buffer_size -syn keyword ngxDirective http2_recv_timeout -syn keyword ngxDirective if_modified_since -syn keyword ngxDirective ignore_invalid_headers -syn keyword ngxDirective image_filter -syn keyword ngxDirective image_filter_buffer -syn keyword ngxDirective image_filter_interlace -syn keyword ngxDirective image_filter_jpeg_quality -syn keyword ngxDirective image_filter_sharpen -syn keyword ngxDirective image_filter_transparency -syn keyword ngxDirective image_filter_webp_quality -syn keyword ngxDirective imap_auth -syn keyword ngxDirective imap_capabilities -syn keyword ngxDirective imap_client_buffer -syn keyword ngxDirective index -syn keyword ngxDirective iocp_threads -syn keyword ngxDirective ip_hash -syn keyword ngxDirective js_access -syn keyword ngxDirective js_content -syn keyword ngxDirective js_filter -syn keyword ngxDirective js_include -syn keyword ngxDirective js_preread -syn keyword ngxDirective js_set -syn keyword ngxDirective keepalive -syn keyword ngxDirective keepalive_disable -syn keyword ngxDirective keepalive_requests -syn keyword ngxDirective keepalive_timeout -syn keyword ngxDirective kqueue_changes -syn keyword ngxDirective kqueue_events -syn keyword ngxDirective large_client_header_buffers -syn keyword ngxDirective least_conn -syn keyword ngxDirective least_time -syn keyword ngxDirective limit_conn -syn keyword ngxDirective limit_conn_log_level -syn keyword ngxDirective limit_conn_status -syn keyword ngxDirective limit_conn_zone -syn keyword ngxDirective limit_rate -syn keyword ngxDirective limit_rate_after -syn keyword ngxDirective limit_req -syn keyword ngxDirective limit_req_log_level -syn keyword ngxDirective limit_req_status -syn keyword ngxDirective limit_req_zone -syn keyword ngxDirective lingering_close -syn keyword ngxDirective lingering_time -syn keyword ngxDirective lingering_timeout -syn keyword ngxDirective load_module -syn keyword ngxDirective lock_file -syn keyword ngxDirective log_format -syn keyword ngxDirective log_not_found -syn keyword ngxDirective log_subrequest -syn keyword ngxDirective map_hash_bucket_size -syn keyword ngxDirective map_hash_max_size -syn keyword ngxDirective match -syn keyword ngxDirective master_process -syn keyword ngxDirective max_ranges -syn keyword ngxDirective memcached_bind -syn keyword ngxDirective memcached_buffer_size -syn keyword ngxDirective memcached_connect_timeout -syn keyword ngxDirective memcached_force_ranges -syn keyword ngxDirective memcached_gzip_flag -syn keyword ngxDirective memcached_next_upstream -syn keyword ngxDirective memcached_next_upstream_timeout -syn keyword ngxDirective memcached_next_upstream_tries -syn keyword ngxDirective memcached_read_timeout -syn keyword ngxDirective memcached_send_timeout -syn keyword ngxDirective merge_slashes -syn keyword ngxDirective min_delete_depth -syn keyword ngxDirective modern_browser -syn keyword ngxDirective modern_browser_value -syn keyword ngxDirective mp4 -syn keyword ngxDirective mp4_buffer_size -syn keyword ngxDirective mp4_max_buffer_size -syn keyword ngxDirective mp4_limit_rate -syn keyword ngxDirective mp4_limit_rate_after -syn keyword ngxDirective msie_padding -syn keyword ngxDirective msie_refresh -syn keyword ngxDirective multi_accept -syn keyword ngxDirective ntlm -syn keyword ngxDirective open_file_cache -syn keyword ngxDirective open_file_cache_errors -syn keyword ngxDirective open_file_cache_events -syn keyword ngxDirective open_file_cache_min_uses -syn keyword ngxDirective open_file_cache_valid -syn keyword ngxDirective open_log_file_cache -syn keyword ngxDirective output_buffers -syn keyword ngxDirective override_charset -syn keyword ngxDirective pcre_jit -syn keyword ngxDirective perl -syn keyword ngxDirective perl_modules -syn keyword ngxDirective perl_require -syn keyword ngxDirective perl_set -syn keyword ngxDirective pid -syn keyword ngxDirective pop3_auth -syn keyword ngxDirective pop3_capabilities -syn keyword ngxDirective port_in_redirect -syn keyword ngxDirective post_acceptex -syn keyword ngxDirective postpone_gzipping -syn keyword ngxDirective postpone_output -syn keyword ngxDirective preread_buffer_size -syn keyword ngxDirective preread_timeout -syn keyword ngxDirective protocol nextgroup=ngxMailProtocol skipwhite -syn keyword ngxMailProtocol imap pop3 smtp contained -syn keyword ngxDirective proxy -syn keyword ngxDirective proxy_bind -syn keyword ngxDirective proxy_buffer -syn keyword ngxDirective proxy_buffer_size -syn keyword ngxDirective proxy_buffering -syn keyword ngxDirective proxy_buffers -syn keyword ngxDirective proxy_busy_buffers_size -syn keyword ngxDirective proxy_cache -syn keyword ngxDirective proxy_cache_bypass -syn keyword ngxDirective proxy_cache_convert_head -syn keyword ngxDirective proxy_cache_key -syn keyword ngxDirective proxy_cache_lock -syn keyword ngxDirective proxy_cache_lock_age -syn keyword ngxDirective proxy_cache_lock_timeout -syn keyword ngxDirective proxy_cache_max_range_offset -syn keyword ngxDirective proxy_cache_methods -syn keyword ngxDirective proxy_cache_min_uses -syn keyword ngxDirective proxy_cache_path -syn keyword ngxDirective proxy_cache_purge -syn keyword ngxDirective proxy_cache_revalidate -syn keyword ngxDirective proxy_cache_use_stale -syn keyword ngxDirective proxy_cache_valid -syn keyword ngxDirective proxy_connect_timeout -syn keyword ngxDirective proxy_cookie_domain -syn keyword ngxDirective proxy_cookie_path -syn keyword ngxDirective proxy_download_rate -syn keyword ngxDirective proxy_force_ranges -syn keyword ngxDirective proxy_headers_hash_bucket_size -syn keyword ngxDirective proxy_headers_hash_max_size -syn keyword ngxDirective proxy_hide_header -syn keyword ngxDirective proxy_http_version -syn keyword ngxDirective proxy_ignore_client_abort -syn keyword ngxDirective proxy_ignore_headers -syn keyword ngxDirective proxy_intercept_errors -syn keyword ngxDirective proxy_limit_rate -syn keyword ngxDirective proxy_max_temp_file_size -syn keyword ngxDirective proxy_method -syn keyword ngxDirective proxy_next_upstream -syn keyword ngxDirective proxy_next_upstream_timeout -syn keyword ngxDirective proxy_next_upstream_tries -syn keyword ngxDirective proxy_no_cache -syn keyword ngxDirective proxy_pass_error_message -syn keyword ngxDirective proxy_pass_header -syn keyword ngxDirective proxy_pass_request_body -syn keyword ngxDirective proxy_pass_request_headers -syn keyword ngxDirective proxy_protocol -syn keyword ngxDirective proxy_protocol_timeout -syn keyword ngxDirective proxy_read_timeout -syn keyword ngxDirective proxy_redirect -syn keyword ngxDirective proxy_request_buffering -syn keyword ngxDirective proxy_responses -syn keyword ngxDirective proxy_send_lowat -syn keyword ngxDirective proxy_send_timeout -syn keyword ngxDirective proxy_set_body -syn keyword ngxDirective proxy_set_header -syn keyword ngxDirective proxy_ssl_certificate -syn keyword ngxDirective proxy_ssl_certificate_key -syn keyword ngxDirective proxy_ssl_ciphers -syn keyword ngxDirective proxy_ssl_crl -syn keyword ngxDirective proxy_ssl_name -syn keyword ngxDirective proxy_ssl_password_file -syn keyword ngxDirective proxy_ssl_protocols nextgroup=ngxSSLProtocol skipwhite -syn keyword ngxDirective proxy_ssl_server_name -syn keyword ngxDirective proxy_ssl_session_reuse -syn keyword ngxDirective proxy_ssl_trusted_certificate -syn keyword ngxDirective proxy_ssl_verify -syn keyword ngxDirective proxy_ssl_verify_depth -syn keyword ngxDirective proxy_store -syn keyword ngxDirective proxy_store_access -syn keyword ngxDirective proxy_temp_file_write_size -syn keyword ngxDirective proxy_temp_path -syn keyword ngxDirective proxy_timeout -syn keyword ngxDirective proxy_upload_rate -syn keyword ngxDirective queue -syn keyword ngxDirective random_index -syn keyword ngxDirective read_ahead -syn keyword ngxDirective real_ip_header -syn keyword ngxDirective real_ip_recursive -syn keyword ngxDirective recursive_error_pages -syn keyword ngxDirective referer_hash_bucket_size -syn keyword ngxDirective referer_hash_max_size -syn keyword ngxDirective request_pool_size -syn keyword ngxDirective reset_timedout_connection -syn keyword ngxDirective resolver -syn keyword ngxDirective resolver_timeout -syn keyword ngxDirective rewrite_log -syn keyword ngxDirective rtsig_overflow_events -syn keyword ngxDirective rtsig_overflow_test -syn keyword ngxDirective rtsig_overflow_threshold -syn keyword ngxDirective rtsig_signo -syn keyword ngxDirective satisfy -syn keyword ngxDirective scgi_bind -syn keyword ngxDirective scgi_buffer_size -syn keyword ngxDirective scgi_buffering -syn keyword ngxDirective scgi_buffers -syn keyword ngxDirective scgi_busy_buffers_size -syn keyword ngxDirective scgi_cache -syn keyword ngxDirective scgi_cache_bypass -syn keyword ngxDirective scgi_cache_key -syn keyword ngxDirective scgi_cache_lock -syn keyword ngxDirective scgi_cache_lock_age -syn keyword ngxDirective scgi_cache_lock_timeout -syn keyword ngxDirective scgi_cache_max_range_offset -syn keyword ngxDirective scgi_cache_methods -syn keyword ngxDirective scgi_cache_min_uses -syn keyword ngxDirective scgi_cache_path -syn keyword ngxDirective scgi_cache_purge -syn keyword ngxDirective scgi_cache_revalidate -syn keyword ngxDirective scgi_cache_use_stale -syn keyword ngxDirective scgi_cache_valid -syn keyword ngxDirective scgi_connect_timeout -syn keyword ngxDirective scgi_force_ranges -syn keyword ngxDirective scgi_hide_header -syn keyword ngxDirective scgi_ignore_client_abort -syn keyword ngxDirective scgi_ignore_headers -syn keyword ngxDirective scgi_intercept_errors -syn keyword ngxDirective scgi_limit_rate -syn keyword ngxDirective scgi_max_temp_file_size -syn keyword ngxDirective scgi_next_upstream -syn keyword ngxDirective scgi_next_upstream_timeout -syn keyword ngxDirective scgi_next_upstream_tries -syn keyword ngxDirective scgi_no_cache -syn keyword ngxDirective scgi_param -syn keyword ngxDirective scgi_pass_header -syn keyword ngxDirective scgi_pass_request_body -syn keyword ngxDirective scgi_pass_request_headers -syn keyword ngxDirective scgi_read_timeout -syn keyword ngxDirective scgi_request_buffering -syn keyword ngxDirective scgi_send_timeout -syn keyword ngxDirective scgi_store -syn keyword ngxDirective scgi_store_access -syn keyword ngxDirective scgi_temp_file_write_size -syn keyword ngxDirective scgi_temp_path -syn keyword ngxDirective secure_link -syn keyword ngxDirective secure_link_md5 -syn keyword ngxDirective secure_link_secret -syn keyword ngxDirective send_lowat -syn keyword ngxDirective send_timeout -syn keyword ngxDirective sendfile -syn keyword ngxDirective sendfile_max_chunk -syn keyword ngxDirective server_name_in_redirect -syn keyword ngxDirective server_names_hash_bucket_size -syn keyword ngxDirective server_names_hash_max_size -syn keyword ngxDirective server_tokens -syn keyword ngxDirective session_log -syn keyword ngxDirective session_log_format -syn keyword ngxDirective session_log_zone -syn keyword ngxDirective set_real_ip_from -syn keyword ngxDirective slice -syn keyword ngxDirective smtp_auth -syn keyword ngxDirective smtp_capabilities -syn keyword ngxDirective smtp_client_buffer -syn keyword ngxDirective smtp_greeting_delay -syn keyword ngxDirective source_charset -syn keyword ngxDirective spdy_chunk_size -syn keyword ngxDirective spdy_headers_comp -syn keyword ngxDirective spdy_keepalive_timeout -syn keyword ngxDirective spdy_max_concurrent_streams -syn keyword ngxDirective spdy_pool_size -syn keyword ngxDirective spdy_recv_buffer_size -syn keyword ngxDirective spdy_recv_timeout -syn keyword ngxDirective spdy_streams_index_size -syn keyword ngxDirective ssi -syn keyword ngxDirective ssi_ignore_recycled_buffers -syn keyword ngxDirective ssi_last_modified -syn keyword ngxDirective ssi_min_file_chunk -syn keyword ngxDirective ssi_silent_errors -syn keyword ngxDirective ssi_types -syn keyword ngxDirective ssi_value_length -syn keyword ngxDirective ssl -syn keyword ngxDirective ssl_buffer_size -syn keyword ngxDirective ssl_certificate -syn keyword ngxDirective ssl_certificate_key -syn keyword ngxDirective ssl_ciphers -syn keyword ngxDirective ssl_client_certificate -syn keyword ngxDirective ssl_crl -syn keyword ngxDirective ssl_dhparam -syn keyword ngxDirective ssl_ecdh_curve -syn keyword ngxDirective ssl_engine -syn keyword ngxDirective ssl_handshake_timeout -syn keyword ngxDirective ssl_password_file -syn keyword ngxDirective ssl_prefer_server_ciphers -syn keyword ngxDirective ssl_preread -syn keyword ngxDirective ssl_protocols nextgroup=ngxSSLProtocol skipwhite -syn keyword ngxSSLProtocol SSLv2 SSLv3 TLSv1 TLSv1.1 TLSv1.2 contained nextgroup=ngxSSLProtocol skipwhite -syn keyword ngxDirective ssl_session_cache -syn keyword ngxDirective ssl_session_ticket_key -syn keyword ngxDirective ssl_session_tickets -syn keyword ngxDirective ssl_session_timeout -syn keyword ngxDirective ssl_stapling -syn keyword ngxDirective ssl_stapling_file -syn keyword ngxDirective ssl_stapling_responder -syn keyword ngxDirective ssl_stapling_verify -syn keyword ngxDirective ssl_trusted_certificate -syn keyword ngxDirective ssl_verify_client -syn keyword ngxDirective ssl_verify_depth -syn keyword ngxDirective starttls -syn keyword ngxDirective state -syn keyword ngxDirective status -syn keyword ngxDirective status_format -syn keyword ngxDirective status_zone -syn keyword ngxDirective sticky -syn keyword ngxDirective sticky_cookie_insert -syn keyword ngxDirective stub_status -syn keyword ngxDirective sub_filter -syn keyword ngxDirective sub_filter_last_modified -syn keyword ngxDirective sub_filter_once -syn keyword ngxDirective sub_filter_types -syn keyword ngxDirective tcp_nodelay -syn keyword ngxDirective tcp_nopush -syn keyword ngxDirective thread_pool -syn keyword ngxDirective thread_stack_size -syn keyword ngxDirective timeout -syn keyword ngxDirective timer_resolution -syn keyword ngxDirective types_hash_bucket_size -syn keyword ngxDirective types_hash_max_size -syn keyword ngxDirective underscores_in_headers -syn keyword ngxDirective uninitialized_variable_warn -syn keyword ngxDirective upstream_conf -syn keyword ngxDirective use -syn keyword ngxDirective user -syn keyword ngxDirective userid -syn keyword ngxDirective userid_domain -syn keyword ngxDirective userid_expires -syn keyword ngxDirective userid_mark -syn keyword ngxDirective userid_name -syn keyword ngxDirective userid_p3p -syn keyword ngxDirective userid_path -syn keyword ngxDirective userid_service -syn keyword ngxDirective uwsgi_bind -syn keyword ngxDirective uwsgi_buffer_size -syn keyword ngxDirective uwsgi_buffering -syn keyword ngxDirective uwsgi_buffers -syn keyword ngxDirective uwsgi_busy_buffers_size -syn keyword ngxDirective uwsgi_cache -syn keyword ngxDirective uwsgi_cache_bypass -syn keyword ngxDirective uwsgi_cache_key -syn keyword ngxDirective uwsgi_cache_lock -syn keyword ngxDirective uwsgi_cache_lock_age -syn keyword ngxDirective uwsgi_cache_lock_timeout -syn keyword ngxDirective uwsgi_cache_methods -syn keyword ngxDirective uwsgi_cache_min_uses -syn keyword ngxDirective uwsgi_cache_path -syn keyword ngxDirective uwsgi_cache_purge -syn keyword ngxDirective uwsgi_cache_revalidate -syn keyword ngxDirective uwsgi_cache_use_stale -syn keyword ngxDirective uwsgi_cache_valid -syn keyword ngxDirective uwsgi_connect_timeout -syn keyword ngxDirective uwsgi_force_ranges -syn keyword ngxDirective uwsgi_hide_header -syn keyword ngxDirective uwsgi_ignore_client_abort -syn keyword ngxDirective uwsgi_ignore_headers -syn keyword ngxDirective uwsgi_intercept_errors -syn keyword ngxDirective uwsgi_limit_rate -syn keyword ngxDirective uwsgi_max_temp_file_size -syn keyword ngxDirective uwsgi_modifier1 -syn keyword ngxDirective uwsgi_modifier2 -syn keyword ngxDirective uwsgi_next_upstream -syn keyword ngxDirective uwsgi_next_upstream_timeout -syn keyword ngxDirective uwsgi_next_upstream_tries -syn keyword ngxDirective uwsgi_no_cache -syn keyword ngxDirective uwsgi_param -syn keyword ngxDirective uwsgi_pass -syn keyword ngxDirective uwsgi_pass_header -syn keyword ngxDirective uwsgi_pass_request_body -syn keyword ngxDirective uwsgi_pass_request_headers -syn keyword ngxDirective uwsgi_read_timeout -syn keyword ngxDirective uwsgi_request_buffering -syn keyword ngxDirective uwsgi_send_timeout -syn keyword ngxDirective uwsgi_ssl_certificate -syn keyword ngxDirective uwsgi_ssl_certificate_key -syn keyword ngxDirective uwsgi_ssl_ciphers -syn keyword ngxDirective uwsgi_ssl_crl -syn keyword ngxDirective uwsgi_ssl_name -syn keyword ngxDirective uwsgi_ssl_password_file -syn keyword ngxDirective uwsgi_ssl_protocols nextgroup=ngxSSLProtocol skipwhite -syn keyword ngxDirective uwsgi_ssl_server_name -syn keyword ngxDirective uwsgi_ssl_session_reuse -syn keyword ngxDirective uwsgi_ssl_trusted_certificate -syn keyword ngxDirective uwsgi_ssl_verify -syn keyword ngxDirective uwsgi_ssl_verify_depth -syn keyword ngxDirective uwsgi_store -syn keyword ngxDirective uwsgi_store_access -syn keyword ngxDirective uwsgi_string -syn keyword ngxDirective uwsgi_temp_file_write_size -syn keyword ngxDirective uwsgi_temp_path -syn keyword ngxDirective valid_referers -syn keyword ngxDirective variables_hash_bucket_size -syn keyword ngxDirective variables_hash_max_size -syn keyword ngxDirective worker_aio_requests -syn keyword ngxDirective worker_connections -syn keyword ngxDirective worker_cpu_affinity -syn keyword ngxDirective worker_priority -syn keyword ngxDirective worker_processes -syn keyword ngxDirective worker_rlimit_core -syn keyword ngxDirective worker_rlimit_nofile -syn keyword ngxDirective worker_rlimit_sigpending -syn keyword ngxDirective worker_threads -syn keyword ngxDirective working_directory -syn keyword ngxDirective xclient -syn keyword ngxDirective xml_entities -syn keyword ngxDirective xslt_last_modified -syn keyword ngxDirective xslt_param -syn keyword ngxDirective xslt_string_param -syn keyword ngxDirective xslt_stylesheet -syn keyword ngxDirective xslt_types -syn keyword ngxDirective zone +syn keyword ngxDirectiveControl contained break +syn keyword ngxDirectiveControl contained return +syn keyword ngxDirectiveControl contained rewrite +syn keyword ngxDirectiveControl contained set + +syn keyword ngxDirectiveError contained error_page +syn keyword ngxDirectiveError contained post_action + +syn keyword ngxDirectiveDeprecated contained connections +syn keyword ngxDirectiveDeprecated contained imap +syn keyword ngxDirectiveDeprecated contained limit_zone +syn keyword ngxDirectiveDeprecated contained mysql_test +syn keyword ngxDirectiveDeprecated contained open_file_cache_retest +syn keyword ngxDirectiveDeprecated contained optimize_server_names +syn keyword ngxDirectiveDeprecated contained satisfy_any +syn keyword ngxDirectiveDeprecated contained so_keepalive + +syn keyword ngxDirective contained absolute_redirect +syn keyword ngxDirective contained accept_mutex +syn keyword ngxDirective contained accept_mutex_delay +syn keyword ngxDirective contained acceptex_read +syn keyword ngxDirective contained access_log +syn keyword ngxDirective contained add_after_body +syn keyword ngxDirective contained add_before_body +syn keyword ngxDirective contained add_header +syn keyword ngxDirective contained addition_types +syn keyword ngxDirective contained aio +syn keyword ngxDirective contained aio_write +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 auth_basic +syn keyword ngxDirective contained auth_basic_user_file +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_key_file +syn keyword ngxDirective contained auth_request +syn keyword ngxDirective contained auth_request_set +syn keyword ngxDirective contained autoindex +syn keyword ngxDirective contained autoindex_exact_size +syn keyword ngxDirective contained autoindex_format +syn keyword ngxDirective contained autoindex_localtime +syn keyword ngxDirective contained charset +syn keyword ngxDirective contained charset_map +syn keyword ngxDirective contained charset_types +syn keyword ngxDirective contained chunked_transfer_encoding +syn keyword ngxDirective contained client_body_buffer_size +syn keyword ngxDirective contained client_body_in_file_only +syn keyword ngxDirective contained client_body_in_single_buffer +syn keyword ngxDirective contained client_body_temp_path +syn keyword ngxDirective contained client_body_timeout +syn keyword ngxDirective contained client_header_buffer_size +syn keyword ngxDirective contained client_header_timeout +syn keyword ngxDirective contained client_max_body_size +syn keyword ngxDirective contained connection_pool_size +syn keyword ngxDirective contained create_full_put_path +syn keyword ngxDirective contained daemon +syn keyword ngxDirective contained dav_access +syn keyword ngxDirective contained dav_methods +syn keyword ngxDirective contained debug_connection +syn keyword ngxDirective contained debug_points +syn keyword ngxDirective contained default_type +syn keyword ngxDirective contained degradation +syn keyword ngxDirective contained degrade +syn keyword ngxDirective contained deny +syn keyword ngxDirective contained devpoll_changes +syn keyword ngxDirective contained devpoll_events +syn keyword ngxDirective contained directio +syn keyword ngxDirective contained directio_alignment +syn keyword ngxDirective contained disable_symlinks +syn keyword ngxDirective contained empty_gif +syn keyword ngxDirective contained env +syn keyword ngxDirective contained epoll_events +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 +syn keyword ngxDirective contained fastcgi_buffers +syn keyword ngxDirective contained fastcgi_busy_buffers_size +syn keyword ngxDirective contained fastcgi_cache +syn keyword ngxDirective contained fastcgi_cache_bypass +syn keyword ngxDirective contained fastcgi_cache_key +syn keyword ngxDirective contained fastcgi_cache_lock +syn keyword ngxDirective contained fastcgi_cache_lock_age +syn keyword ngxDirective contained fastcgi_cache_lock_timeout +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 +syn keyword ngxDirective contained fastcgi_catch_stderr +syn keyword ngxDirective contained fastcgi_connect_timeout +syn keyword ngxDirective contained fastcgi_force_ranges +syn keyword ngxDirective contained fastcgi_hide_header +syn keyword ngxDirective contained fastcgi_ignore_client_abort +syn keyword ngxDirective contained fastcgi_ignore_headers +syn keyword ngxDirective contained fastcgi_index +syn keyword ngxDirective contained fastcgi_intercept_errors +syn keyword ngxDirective contained fastcgi_keep_conn +syn keyword ngxDirective contained fastcgi_limit_rate +syn keyword ngxDirective contained fastcgi_max_temp_file_size +syn keyword ngxDirective contained fastcgi_next_upstream +syn keyword ngxDirective contained fastcgi_next_upstream_timeout +syn keyword ngxDirective contained fastcgi_next_upstream_tries +syn keyword ngxDirective contained fastcgi_no_cache +syn keyword ngxDirective contained fastcgi_param +syn keyword ngxDirective contained fastcgi_pass_header +syn keyword ngxDirective contained fastcgi_pass_request_body +syn keyword ngxDirective contained fastcgi_pass_request_headers +syn keyword ngxDirective contained fastcgi_read_timeout +syn keyword ngxDirective contained fastcgi_request_buffering +syn keyword ngxDirective contained fastcgi_send_lowat +syn keyword ngxDirective contained fastcgi_send_timeout +syn keyword ngxDirective contained fastcgi_split_path_info +syn keyword ngxDirective contained fastcgi_store +syn keyword ngxDirective contained fastcgi_store_access +syn keyword ngxDirective contained fastcgi_temp_file_write_size +syn keyword ngxDirective contained fastcgi_temp_path +syn keyword ngxDirective contained flv +syn keyword ngxDirective contained geoip_city +syn keyword ngxDirective contained geoip_country +syn keyword ngxDirective contained geoip_org +syn keyword ngxDirective contained geoip_proxy +syn keyword ngxDirective contained geoip_proxy_recursive +syn keyword ngxDirective contained google_perftools_profiles +syn keyword ngxDirective contained gunzip +syn keyword ngxDirective contained gunzip_buffers +syn keyword ngxDirective contained gzip +syn keyword ngxDirective contained gzip_buffers +syn keyword ngxDirective contained gzip_comp_level +syn keyword ngxDirective contained gzip_disable +syn keyword ngxDirective contained gzip_hash +syn keyword ngxDirective contained gzip_http_version +syn keyword ngxDirective contained gzip_min_length +syn keyword ngxDirective contained gzip_no_buffer +syn keyword ngxDirective contained gzip_proxied +syn keyword ngxDirective contained gzip_static +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_chunk_size +syn keyword ngxDirective contained http2_body_preread_size +syn keyword ngxDirective contained http2_idle_timeout +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_recv_buffer_size +syn keyword ngxDirective contained http2_recv_timeout +syn keyword ngxDirective contained if_modified_since +syn keyword ngxDirective contained ignore_invalid_headers +syn keyword ngxDirective contained image_filter +syn keyword ngxDirective contained image_filter_buffer +syn keyword ngxDirective contained image_filter_interlace +syn keyword ngxDirective contained image_filter_jpeg_quality +syn keyword ngxDirective contained image_filter_sharpen +syn keyword ngxDirective contained image_filter_transparency +syn keyword ngxDirective contained image_filter_webp_quality +syn keyword ngxDirective contained imap_auth +syn keyword ngxDirective contained imap_capabilities +syn keyword ngxDirective contained imap_client_buffer +syn keyword ngxDirective contained index +syn keyword ngxDirective contained iocp_threads +syn keyword ngxDirective contained ip_hash +syn keyword ngxDirective contained js_access +syn keyword ngxDirective contained js_content +syn keyword ngxDirective contained js_filter +syn keyword ngxDirective contained js_include +syn keyword ngxDirective contained js_preread +syn keyword ngxDirective contained js_set +syn keyword ngxDirective contained keepalive +syn keyword ngxDirective contained keepalive_disable +syn keyword ngxDirective contained keepalive_requests +syn keyword ngxDirective contained keepalive_timeout +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_log_level +syn keyword ngxDirective contained limit_conn_status +syn keyword ngxDirective contained limit_conn_zone +syn keyword ngxDirective contained limit_rate +syn keyword ngxDirective contained limit_rate_after +syn keyword ngxDirective contained limit_req +syn keyword ngxDirective contained limit_req_log_level +syn keyword ngxDirective contained limit_req_status +syn keyword ngxDirective contained limit_req_zone +syn keyword ngxDirective contained lingering_close +syn keyword ngxDirective contained lingering_time +syn keyword ngxDirective contained lingering_timeout +syn keyword ngxDirective contained load_module +syn keyword ngxDirective contained lock_file +syn keyword ngxDirective contained log_format +syn keyword ngxDirective contained log_not_found +syn keyword ngxDirective contained log_subrequest +syn keyword ngxDirective contained map_hash_bucket_size +syn keyword ngxDirective contained map_hash_max_size +syn keyword ngxDirective contained match +syn keyword ngxDirective contained master_process +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 +syn keyword ngxDirective contained memcached_next_upstream_tries +syn keyword ngxDirective contained memcached_read_timeout +syn keyword ngxDirective contained memcached_send_timeout +syn keyword ngxDirective contained merge_slashes +syn keyword ngxDirective contained min_delete_depth +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_max_buffer_size +syn keyword ngxDirective contained mp4_limit_rate +syn keyword ngxDirective contained mp4_limit_rate_after +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 +syn keyword ngxDirective contained open_file_cache_min_uses +syn keyword ngxDirective contained open_file_cache_valid +syn keyword ngxDirective contained open_log_file_cache +syn keyword ngxDirective contained output_buffers +syn keyword ngxDirective contained override_charset +syn keyword ngxDirective contained pcre_jit +syn keyword ngxDirective contained perl +syn keyword ngxDirective contained perl_modules +syn keyword ngxDirective contained perl_require +syn keyword ngxDirective contained perl_set +syn keyword ngxDirective contained pid +syn keyword ngxDirective contained pop3_auth +syn keyword ngxDirective contained pop3_capabilities +syn keyword ngxDirective contained port_in_redirect +syn keyword ngxDirective contained post_acceptex +syn keyword ngxDirective contained postpone_gzipping +syn keyword ngxDirective contained postpone_output +syn keyword ngxDirective contained preread_buffer_size +syn keyword ngxDirective contained preread_timeout +syn keyword ngxDirective contained protocol +syn keyword ngxDirective contained proxy +syn keyword ngxDirective contained proxy_bind +syn keyword ngxDirective contained proxy_buffer +syn keyword ngxDirective contained proxy_buffer_size +syn keyword ngxDirective contained proxy_buffering +syn keyword ngxDirective contained proxy_buffers +syn keyword ngxDirective contained proxy_busy_buffers_size +syn keyword ngxDirective contained proxy_cache +syn keyword ngxDirective contained proxy_cache_bypass +syn keyword ngxDirective contained proxy_cache_convert_head +syn keyword ngxDirective contained proxy_cache_key +syn keyword ngxDirective contained proxy_cache_lock +syn keyword ngxDirective contained proxy_cache_lock_age +syn keyword ngxDirective contained proxy_cache_lock_timeout +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 +syn keyword ngxDirective contained proxy_connect_timeout +syn keyword ngxDirective contained proxy_cookie_domain +syn keyword ngxDirective contained proxy_cookie_path +syn keyword ngxDirective contained proxy_download_rate +syn keyword ngxDirective contained proxy_force_ranges +syn keyword ngxDirective contained proxy_headers_hash_bucket_size +syn keyword ngxDirective contained proxy_headers_hash_max_size +syn keyword ngxDirective contained proxy_hide_header +syn keyword ngxDirective contained proxy_http_version +syn keyword ngxDirective contained proxy_ignore_client_abort +syn keyword ngxDirective contained proxy_ignore_headers +syn keyword ngxDirective contained proxy_intercept_errors +syn keyword ngxDirective contained proxy_limit_rate +syn keyword ngxDirective contained proxy_max_temp_file_size +syn keyword ngxDirective contained proxy_method +syn keyword ngxDirective contained proxy_next_upstream +syn keyword ngxDirective contained proxy_next_upstream_timeout +syn keyword ngxDirective contained proxy_next_upstream_tries +syn keyword ngxDirective contained proxy_no_cache +syn keyword ngxDirective contained proxy_pass_error_message +syn keyword ngxDirective contained proxy_pass_header +syn keyword ngxDirective contained proxy_pass_request_body +syn keyword ngxDirective contained proxy_pass_request_headers +syn keyword ngxDirective contained proxy_protocol +syn keyword ngxDirective contained proxy_protocol_timeout +syn keyword ngxDirective contained proxy_read_timeout +syn keyword ngxDirective contained proxy_redirect +syn keyword ngxDirective contained proxy_request_buffering +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_set_body +syn keyword ngxDirective contained proxy_set_header +syn keyword ngxDirective contained proxy_ssl_certificate +syn keyword ngxDirective contained proxy_ssl_certificate_key +syn keyword ngxDirective contained proxy_ssl_ciphers +syn keyword ngxDirective contained proxy_ssl_crl +syn keyword ngxDirective contained proxy_ssl_name +syn keyword ngxDirective contained proxy_ssl_password_file +syn keyword ngxDirective contained proxy_ssl_protocols +syn keyword ngxDirective contained proxy_ssl_server_name +syn keyword ngxDirective contained proxy_ssl_session_reuse +syn keyword ngxDirective contained proxy_ssl_trusted_certificate +syn keyword ngxDirective contained proxy_ssl_verify +syn keyword ngxDirective contained proxy_ssl_verify_depth +syn keyword ngxDirective contained proxy_store +syn keyword ngxDirective contained proxy_store_access +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 random_index +syn keyword ngxDirective contained read_ahead +syn keyword ngxDirective contained real_ip_header +syn keyword ngxDirective contained real_ip_recursive +syn keyword ngxDirective contained recursive_error_pages +syn keyword ngxDirective contained referer_hash_bucket_size +syn keyword ngxDirective contained referer_hash_max_size +syn keyword ngxDirective contained request_pool_size +syn keyword ngxDirective contained reset_timedout_connection +syn keyword ngxDirective contained resolver +syn keyword ngxDirective contained resolver_timeout +syn keyword ngxDirective contained rewrite_log +syn keyword ngxDirective contained rtsig_overflow_events +syn keyword ngxDirective contained rtsig_overflow_test +syn keyword ngxDirective contained rtsig_overflow_threshold +syn keyword ngxDirective contained rtsig_signo +syn keyword ngxDirective contained satisfy +syn keyword ngxDirective contained scgi_bind +syn keyword ngxDirective contained scgi_buffer_size +syn keyword ngxDirective contained scgi_buffering +syn keyword ngxDirective contained scgi_buffers +syn keyword ngxDirective contained scgi_busy_buffers_size +syn keyword ngxDirective contained scgi_cache +syn keyword ngxDirective contained scgi_cache_bypass +syn keyword ngxDirective contained scgi_cache_key +syn keyword ngxDirective contained scgi_cache_lock +syn keyword ngxDirective contained scgi_cache_lock_age +syn keyword ngxDirective contained scgi_cache_lock_timeout +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 +syn keyword ngxDirective contained scgi_connect_timeout +syn keyword ngxDirective contained scgi_force_ranges +syn keyword ngxDirective contained scgi_hide_header +syn keyword ngxDirective contained scgi_ignore_client_abort +syn keyword ngxDirective contained scgi_ignore_headers +syn keyword ngxDirective contained scgi_intercept_errors +syn keyword ngxDirective contained scgi_limit_rate +syn keyword ngxDirective contained scgi_max_temp_file_size +syn keyword ngxDirective contained scgi_next_upstream +syn keyword ngxDirective contained scgi_next_upstream_timeout +syn keyword ngxDirective contained scgi_next_upstream_tries +syn keyword ngxDirective contained scgi_no_cache +syn keyword ngxDirective contained scgi_param +syn keyword ngxDirective contained scgi_pass_header +syn keyword ngxDirective contained scgi_pass_request_body +syn keyword ngxDirective contained scgi_pass_request_headers +syn keyword ngxDirective contained scgi_read_timeout +syn keyword ngxDirective contained scgi_request_buffering +syn keyword ngxDirective contained scgi_send_timeout +syn keyword ngxDirective contained scgi_store +syn keyword ngxDirective contained scgi_store_access +syn keyword ngxDirective contained scgi_temp_file_write_size +syn keyword ngxDirective contained scgi_temp_path +syn keyword ngxDirective contained secure_link +syn keyword ngxDirective contained secure_link_md5 +syn keyword ngxDirective contained secure_link_secret +syn keyword ngxDirective contained send_lowat +syn keyword ngxDirective contained send_timeout +syn keyword ngxDirective contained sendfile +syn keyword ngxDirective contained sendfile_max_chunk +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 +syn keyword ngxDirective contained smtp_capabilities +syn keyword ngxDirective contained smtp_client_buffer +syn keyword ngxDirective contained smtp_greeting_delay +syn keyword ngxDirective contained source_charset +syn keyword ngxDirective contained spdy_chunk_size +syn keyword ngxDirective contained spdy_headers_comp +syn keyword ngxDirective contained spdy_keepalive_timeout +syn keyword ngxDirective contained spdy_max_concurrent_streams +syn keyword ngxDirective contained spdy_pool_size +syn keyword ngxDirective contained spdy_recv_buffer_size +syn keyword ngxDirective contained spdy_recv_timeout +syn keyword ngxDirective contained spdy_streams_index_size +syn keyword ngxDirective contained ssi +syn keyword ngxDirective contained ssi_ignore_recycled_buffers +syn keyword ngxDirective contained ssi_last_modified +syn keyword ngxDirective contained ssi_min_file_chunk +syn keyword ngxDirective contained ssi_silent_errors +syn keyword ngxDirective contained ssi_types +syn keyword ngxDirective contained ssi_value_length +syn keyword ngxDirective contained ssl +syn keyword ngxDirective contained ssl_buffer_size +syn keyword ngxDirective contained ssl_certificate +syn keyword ngxDirective contained ssl_certificate_key +syn keyword ngxDirective contained ssl_ciphers +syn keyword ngxDirective contained ssl_client_certificate +syn keyword ngxDirective contained ssl_crl +syn keyword ngxDirective contained ssl_dhparam +syn keyword ngxDirective contained ssl_ecdh_curve +syn keyword ngxDirective contained ssl_engine +syn keyword ngxDirective contained ssl_handshake_timeout +syn keyword ngxDirective contained ssl_password_file +syn keyword ngxDirective contained ssl_prefer_server_ciphers +syn keyword ngxDirective contained ssl_preread +syn keyword ngxDirective contained ssl_protocols +syn keyword ngxDirective contained ssl_session_cache +syn keyword ngxDirective contained ssl_session_ticket_key +syn keyword ngxDirective contained ssl_session_tickets +syn keyword ngxDirective contained ssl_session_timeout +syn keyword ngxDirective contained ssl_stapling +syn keyword ngxDirective contained ssl_stapling_file +syn keyword ngxDirective contained ssl_stapling_responder +syn keyword ngxDirective contained ssl_stapling_verify +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 sticky_cookie_insert +syn keyword ngxDirective contained stub_status +syn keyword ngxDirective contained sub_filter +syn keyword ngxDirective contained sub_filter_last_modified +syn keyword ngxDirective contained sub_filter_once +syn keyword ngxDirective contained sub_filter_types +syn keyword ngxDirective contained tcp_nodelay +syn keyword ngxDirective contained tcp_nopush +syn keyword ngxDirective contained thread_pool +syn keyword ngxDirective contained thread_stack_size +syn keyword ngxDirective contained timeout +syn keyword ngxDirective contained timer_resolution +syn keyword ngxDirective contained types_hash_bucket_size +syn keyword ngxDirective contained types_hash_max_size +syn keyword ngxDirective contained underscores_in_headers +syn keyword ngxDirective contained uninitialized_variable_warn +syn keyword ngxDirective contained upstream_conf +syn keyword ngxDirective contained use +syn keyword ngxDirective contained user +syn keyword ngxDirective contained userid +syn keyword ngxDirective contained userid_domain +syn keyword ngxDirective contained userid_expires +syn keyword ngxDirective contained userid_mark +syn keyword ngxDirective contained userid_name +syn keyword ngxDirective contained userid_p3p +syn keyword ngxDirective contained userid_path +syn keyword ngxDirective contained userid_service +syn keyword ngxDirective contained uwsgi_bind +syn keyword ngxDirective contained uwsgi_buffer_size +syn keyword ngxDirective contained uwsgi_buffering +syn keyword ngxDirective contained uwsgi_buffers +syn keyword ngxDirective contained uwsgi_busy_buffers_size +syn keyword ngxDirective contained uwsgi_cache +syn keyword ngxDirective contained uwsgi_cache_bypass +syn keyword ngxDirective contained uwsgi_cache_key +syn keyword ngxDirective contained uwsgi_cache_lock +syn keyword ngxDirective contained uwsgi_cache_lock_age +syn keyword ngxDirective contained uwsgi_cache_lock_timeout +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 +syn keyword ngxDirective contained uwsgi_connect_timeout +syn keyword ngxDirective contained uwsgi_force_ranges +syn keyword ngxDirective contained uwsgi_hide_header +syn keyword ngxDirective contained uwsgi_ignore_client_abort +syn keyword ngxDirective contained uwsgi_ignore_headers +syn keyword ngxDirective contained uwsgi_intercept_errors +syn keyword ngxDirective contained uwsgi_limit_rate +syn keyword ngxDirective contained uwsgi_max_temp_file_size +syn keyword ngxDirective contained uwsgi_modifier1 +syn keyword ngxDirective contained uwsgi_modifier2 +syn keyword ngxDirective contained uwsgi_next_upstream +syn keyword ngxDirective contained uwsgi_next_upstream_timeout +syn keyword ngxDirective contained uwsgi_next_upstream_tries +syn keyword ngxDirective contained uwsgi_no_cache +syn keyword ngxDirective contained uwsgi_param +syn keyword ngxDirective contained uwsgi_pass +syn keyword ngxDirective contained uwsgi_pass_header +syn keyword ngxDirective contained uwsgi_pass_request_body +syn keyword ngxDirective contained uwsgi_pass_request_headers +syn keyword ngxDirective contained uwsgi_read_timeout +syn keyword ngxDirective contained uwsgi_request_buffering +syn keyword ngxDirective contained uwsgi_send_timeout +syn keyword ngxDirective contained uwsgi_ssl_certificate +syn keyword ngxDirective contained uwsgi_ssl_certificate_key +syn keyword ngxDirective contained uwsgi_ssl_ciphers +syn keyword ngxDirective contained uwsgi_ssl_crl +syn keyword ngxDirective contained uwsgi_ssl_name +syn keyword ngxDirective contained uwsgi_ssl_password_file +syn keyword ngxDirective contained uwsgi_ssl_protocols +syn keyword ngxDirective contained uwsgi_ssl_server_name +syn keyword ngxDirective contained uwsgi_ssl_session_reuse +syn keyword ngxDirective contained uwsgi_ssl_trusted_certificate +syn keyword ngxDirective contained uwsgi_ssl_verify +syn keyword ngxDirective contained uwsgi_ssl_verify_depth +syn keyword ngxDirective contained uwsgi_store +syn keyword ngxDirective contained uwsgi_store_access +syn keyword ngxDirective contained uwsgi_string +syn keyword ngxDirective contained uwsgi_temp_file_write_size +syn keyword ngxDirective contained uwsgi_temp_path +syn keyword ngxDirective contained valid_referers +syn keyword ngxDirective contained variables_hash_bucket_size +syn keyword ngxDirective contained variables_hash_max_size +syn keyword ngxDirective contained worker_aio_requests +syn keyword ngxDirective contained worker_connections +syn keyword ngxDirective contained worker_cpu_affinity +syn keyword ngxDirective contained worker_priority +syn keyword ngxDirective contained worker_processes +syn keyword ngxDirective contained worker_rlimit_core +syn keyword ngxDirective contained worker_rlimit_nofile +syn keyword ngxDirective contained worker_rlimit_sigpending +syn keyword ngxDirective contained worker_threads +syn keyword ngxDirective contained working_directory +syn keyword ngxDirective contained xclient +syn keyword ngxDirective contained xml_entities +syn keyword ngxDirective contained xslt_last_modified +syn keyword ngxDirective contained xslt_param +syn keyword ngxDirective contained xslt_string_param +syn keyword ngxDirective contained xslt_stylesheet +syn keyword ngxDirective contained xslt_types +syn keyword ngxDirective contained zone " 3rd party module list: " https://www.nginx.com/resources/wiki/modules/ " Accept Language Module " Parses the Accept-Language header and gives the most suitable locale from a list of supported locales. -syn keyword ngxDirectiveThirdParty set_from_accept_language +syn keyword ngxDirectiveThirdParty contained set_from_accept_language " Access Key Module (DEPRECATED) " Denies access unless the request URL contains an access key. -syn keyword ngxDirectiveDeprecated accesskey -syn keyword ngxDirectiveDeprecated accesskey_arg -syn keyword ngxDirectiveDeprecated accesskey_hashmethod -syn keyword ngxDirectiveDeprecated accesskey_signature +syn keyword ngxDirectiveDeprecated contained accesskey +syn keyword ngxDirectiveDeprecated contained accesskey_arg +syn keyword ngxDirectiveDeprecated contained accesskey_hashmethod +syn keyword ngxDirectiveDeprecated contained accesskey_signature " Asynchronous FastCGI Module " Primarily a modified version of the Nginx FastCGI module which implements multiplexing of connections, allowing a single FastCGI server to handle many concurrent requests. -" syn keyword ngxDirectiveThirdParty fastcgi_bind -" syn keyword ngxDirectiveThirdParty fastcgi_buffer_size -" syn keyword ngxDirectiveThirdParty fastcgi_buffers -" syn keyword ngxDirectiveThirdParty fastcgi_busy_buffers_size -" syn keyword ngxDirectiveThirdParty fastcgi_cache -" syn keyword ngxDirectiveThirdParty fastcgi_cache_key -" syn keyword ngxDirectiveThirdParty fastcgi_cache_methods -" syn keyword ngxDirectiveThirdParty fastcgi_cache_min_uses -" syn keyword ngxDirectiveThirdParty fastcgi_cache_path -" syn keyword ngxDirectiveThirdParty fastcgi_cache_use_stale -" syn keyword ngxDirectiveThirdParty fastcgi_cache_valid -" syn keyword ngxDirectiveThirdParty fastcgi_catch_stderr -" syn keyword ngxDirectiveThirdParty fastcgi_connect_timeout -" syn keyword ngxDirectiveThirdParty fastcgi_hide_header -" syn keyword ngxDirectiveThirdParty fastcgi_ignore_client_abort -" syn keyword ngxDirectiveThirdParty fastcgi_ignore_headers -" syn keyword ngxDirectiveThirdParty fastcgi_index -" syn keyword ngxDirectiveThirdParty fastcgi_intercept_errors -" syn keyword ngxDirectiveThirdParty fastcgi_max_temp_file_size -" syn keyword ngxDirectiveThirdParty fastcgi_next_upstream -" syn keyword ngxDirectiveThirdParty fastcgi_param -" syn keyword ngxDirectiveThirdParty fastcgi_pass -" syn keyword ngxDirectiveThirdParty fastcgi_pass_header -" syn keyword ngxDirectiveThirdParty fastcgi_pass_request_body -" syn keyword ngxDirectiveThirdParty fastcgi_pass_request_headers -" syn keyword ngxDirectiveThirdParty fastcgi_read_timeout -" syn keyword ngxDirectiveThirdParty fastcgi_send_lowat -" syn keyword ngxDirectiveThirdParty fastcgi_send_timeout -" syn keyword ngxDirectiveThirdParty fastcgi_split_path_info -" syn keyword ngxDirectiveThirdParty fastcgi_store -" syn keyword ngxDirectiveThirdParty fastcgi_store_access -" syn keyword ngxDirectiveThirdParty fastcgi_temp_file_write_size -" syn keyword ngxDirectiveThirdParty fastcgi_temp_path -syn keyword ngxDirectiveDeprecated fastcgi_upstream_fail_timeout -syn keyword ngxDirectiveDeprecated fastcgi_upstream_max_fails +" syn keyword ngxDirectiveThirdParty contained fastcgi_bind +" syn keyword ngxDirectiveThirdParty contained fastcgi_buffer_size +" syn keyword ngxDirectiveThirdParty contained fastcgi_buffers +" syn keyword ngxDirectiveThirdParty contained fastcgi_busy_buffers_size +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache_key +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache_methods +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache_min_uses +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache_path +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache_use_stale +" syn keyword ngxDirectiveThirdParty contained fastcgi_cache_valid +" syn keyword ngxDirectiveThirdParty contained fastcgi_catch_stderr +" syn keyword ngxDirectiveThirdParty contained fastcgi_connect_timeout +" syn keyword ngxDirectiveThirdParty contained fastcgi_hide_header +" syn keyword ngxDirectiveThirdParty contained fastcgi_ignore_client_abort +" syn keyword ngxDirectiveThirdParty contained fastcgi_ignore_headers +" syn keyword ngxDirectiveThirdParty contained fastcgi_index +" syn keyword ngxDirectiveThirdParty contained fastcgi_intercept_errors +" syn keyword ngxDirectiveThirdParty contained fastcgi_max_temp_file_size +" syn keyword ngxDirectiveThirdParty contained fastcgi_next_upstream +" syn keyword ngxDirectiveThirdParty contained fastcgi_param +" syn keyword ngxDirectiveThirdParty contained fastcgi_pass +" syn keyword ngxDirectiveThirdParty contained fastcgi_pass_header +" syn keyword ngxDirectiveThirdParty contained fastcgi_pass_request_body +" syn keyword ngxDirectiveThirdParty contained fastcgi_pass_request_headers +" syn keyword ngxDirectiveThirdParty contained fastcgi_read_timeout +" syn keyword ngxDirectiveThirdParty contained fastcgi_send_lowat +" syn keyword ngxDirectiveThirdParty contained fastcgi_send_timeout +" syn keyword ngxDirectiveThirdParty contained fastcgi_split_path_info +" syn keyword ngxDirectiveThirdParty contained fastcgi_store +" syn keyword ngxDirectiveThirdParty contained fastcgi_store_access +" syn keyword ngxDirectiveThirdParty contained fastcgi_temp_file_write_size +" syn keyword ngxDirectiveThirdParty contained fastcgi_temp_path +syn keyword ngxDirectiveDeprecated contained fastcgi_upstream_fail_timeout +syn keyword ngxDirectiveDeprecated contained fastcgi_upstream_max_fails " Akamai G2O Module " Nginx Module for Authenticating Akamai G2O requests -syn keyword ngxDirectiveThirdParty g2o -syn keyword ngxDirectiveThirdParty g2o_nonce -syn keyword ngxDirectiveThirdParty g2o_key +syn keyword ngxDirectiveThirdParty contained g2o +syn keyword ngxDirectiveThirdParty contained g2o_nonce +syn keyword ngxDirectiveThirdParty contained g2o_key " Lua Module " You can be very simple to execute lua code for nginx -syn keyword ngxDirectiveThirdParty lua_file +syn keyword ngxDirectiveThirdParty contained lua_file " Array Variable Module " Add support for array-typed variables to nginx config files -syn keyword ngxDirectiveThirdParty array_split -syn keyword ngxDirectiveThirdParty array_join -syn keyword ngxDirectiveThirdParty array_map -syn keyword ngxDirectiveThirdParty array_map_op +syn keyword ngxDirectiveThirdParty contained array_split +syn keyword ngxDirectiveThirdParty contained array_join +syn keyword ngxDirectiveThirdParty contained array_map +syn keyword ngxDirectiveThirdParty contained array_map_op " Nginx Audio Track for HTTP Live Streaming " This nginx module generates audio track for hls streams on the fly. -syn keyword ngxDirectiveThirdParty ngx_hls_audio_track -syn keyword ngxDirectiveThirdParty ngx_hls_audio_track_rootpath -syn keyword ngxDirectiveThirdParty ngx_hls_audio_track_output_format -syn keyword ngxDirectiveThirdParty ngx_hls_audio_track_output_header +syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track +syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_rootpath +syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_output_format +syn keyword ngxDirectiveThirdParty contained ngx_hls_audio_track_output_header " AWS Proxy Module " Nginx module to proxy to authenticated AWS services -syn keyword ngxDirectiveThirdParty aws_access_key -syn keyword ngxDirectiveThirdParty aws_key_scope -syn keyword ngxDirectiveThirdParty aws_signing_key -syn keyword ngxDirectiveThirdParty aws_endpoint -syn keyword ngxDirectiveThirdParty aws_s3_bucket -syn keyword ngxDirectiveThirdParty aws_sign +syn keyword ngxDirectiveThirdParty contained aws_access_key +syn keyword ngxDirectiveThirdParty contained aws_key_scope +syn keyword ngxDirectiveThirdParty contained aws_signing_key +syn keyword ngxDirectiveThirdParty contained aws_endpoint +syn keyword ngxDirectiveThirdParty contained aws_s3_bucket +syn keyword ngxDirectiveThirdParty contained aws_sign " Backtrace module " A Nginx module to dump backtrace when a worker process exits abnormally -syn keyword ngxDirectiveThirdParty backtrace_log -syn keyword ngxDirectiveThirdParty backtrace_max_stack_size +syn keyword ngxDirectiveThirdParty contained backtrace_log +syn keyword ngxDirectiveThirdParty contained backtrace_max_stack_size " Brotli Module " Nginx module for Brotli compression -syn keyword ngxDirectiveThirdParty brotli_static -syn keyword ngxDirectiveThirdParty brotli -syn keyword ngxDirectiveThirdParty brotli_types -syn keyword ngxDirectiveThirdParty brotli_buffers -syn keyword ngxDirectiveThirdParty brotli_comp_level -syn keyword ngxDirectiveThirdParty brotli_window -syn keyword ngxDirectiveThirdParty brotli_min_length +syn keyword ngxDirectiveThirdParty contained brotli_static +syn keyword ngxDirectiveThirdParty contained brotli +syn keyword ngxDirectiveThirdParty contained brotli_types +syn keyword ngxDirectiveThirdParty contained brotli_buffers +syn keyword ngxDirectiveThirdParty contained brotli_comp_level +syn keyword ngxDirectiveThirdParty contained brotli_window +syn keyword ngxDirectiveThirdParty contained brotli_min_length " Cache Purge Module " Adds ability to purge content from FastCGI, proxy, SCGI and uWSGI caches. -syn keyword ngxDirectiveThirdParty fastcgi_cache_purge -syn keyword ngxDirectiveThirdParty proxy_cache_purge -" syn keyword ngxDirectiveThirdParty scgi_cache_purge -" syn keyword ngxDirectiveThirdParty uwsgi_cache_purge +syn keyword ngxDirectiveThirdParty contained fastcgi_cache_purge +syn keyword ngxDirectiveThirdParty contained proxy_cache_purge +" syn keyword ngxDirectiveThirdParty contained scgi_cache_purge +" syn keyword ngxDirectiveThirdParty contained uwsgi_cache_purge " Chunkin Module (DEPRECATED) " HTTP 1.1 chunked-encoding request body support for Nginx. -syn keyword ngxDirectiveDeprecated chunkin -syn keyword ngxDirectiveDeprecated chunkin_keepalive -syn keyword ngxDirectiveDeprecated chunkin_max_chunks_per_buf -syn keyword ngxDirectiveDeprecated chunkin_resume +syn keyword ngxDirectiveDeprecated contained chunkin +syn keyword ngxDirectiveDeprecated contained chunkin_keepalive +syn keyword ngxDirectiveDeprecated contained chunkin_max_chunks_per_buf +syn keyword ngxDirectiveDeprecated contained chunkin_resume " Circle GIF Module " Generates simple circle images with the colors and size specified in the URL. -syn keyword ngxDirectiveThirdParty circle_gif -syn keyword ngxDirectiveThirdParty circle_gif_max_radius -syn keyword ngxDirectiveThirdParty circle_gif_min_radius -syn keyword ngxDirectiveThirdParty circle_gif_step_radius +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 " Nginx-Clojure Module " Parses the Accept-Language header and gives the most suitable locale from a list of supported locales. -syn keyword ngxDirectiveThirdParty jvm_path -syn keyword ngxDirectiveThirdParty jvm_var -syn keyword ngxDirectiveThirdParty jvm_classpath -syn keyword ngxDirectiveThirdParty jvm_classpath_check -syn keyword ngxDirectiveThirdParty jvm_workers -syn keyword ngxDirectiveThirdParty jvm_options -syn keyword ngxDirectiveThirdParty jvm_handler_type -syn keyword ngxDirectiveThirdParty jvm_init_handler_name -syn keyword ngxDirectiveThirdParty jvm_init_handler_code -syn keyword ngxDirectiveThirdParty jvm_exit_handler_name -syn keyword ngxDirectiveThirdParty jvm_exit_handler_code -syn keyword ngxDirectiveThirdParty handlers_lazy_init -syn keyword ngxDirectiveThirdParty auto_upgrade_ws -syn keyword ngxDirectiveThirdParty content_handler_type -syn keyword ngxDirectiveThirdParty content_handler_name -syn keyword ngxDirectiveThirdParty content_handler_code -syn keyword ngxDirectiveThirdParty rewrite_handler_type -syn keyword ngxDirectiveThirdParty rewrite_handler_name -syn keyword ngxDirectiveThirdParty rewrite_handler_code -syn keyword ngxDirectiveThirdParty access_handler_type -syn keyword ngxDirectiveThirdParty access_handler_name -syn keyword ngxDirectiveThirdParty access_handler_code -syn keyword ngxDirectiveThirdParty header_filter_type -syn keyword ngxDirectiveThirdParty header_filter_name -syn keyword ngxDirectiveThirdParty header_filter_code -syn keyword ngxDirectiveThirdParty content_handler_property -syn keyword ngxDirectiveThirdParty rewrite_handler_property -syn keyword ngxDirectiveThirdParty access_handler_property -syn keyword ngxDirectiveThirdParty header_filter_property -syn keyword ngxDirectiveThirdParty always_read_body -syn keyword ngxDirectiveThirdParty shared_map -syn keyword ngxDirectiveThirdParty write_page_size +syn keyword ngxDirectiveThirdParty contained jvm_path +syn keyword ngxDirectiveThirdParty contained jvm_var +syn keyword ngxDirectiveThirdParty contained jvm_classpath +syn keyword ngxDirectiveThirdParty contained jvm_classpath_check +syn keyword ngxDirectiveThirdParty contained jvm_workers +syn keyword ngxDirectiveThirdParty contained jvm_options +syn keyword ngxDirectiveThirdParty contained jvm_handler_type +syn keyword ngxDirectiveThirdParty contained jvm_init_handler_name +syn keyword ngxDirectiveThirdParty contained jvm_init_handler_code +syn keyword ngxDirectiveThirdParty contained jvm_exit_handler_name +syn keyword ngxDirectiveThirdParty contained jvm_exit_handler_code +syn keyword ngxDirectiveThirdParty contained handlers_lazy_init +syn keyword ngxDirectiveThirdParty contained auto_upgrade_ws +syn keyword ngxDirectiveThirdParty contained content_handler_type +syn keyword ngxDirectiveThirdParty contained content_handler_name +syn keyword ngxDirectiveThirdParty contained content_handler_code +syn keyword ngxDirectiveThirdParty contained rewrite_handler_type +syn keyword ngxDirectiveThirdParty contained rewrite_handler_name +syn keyword ngxDirectiveThirdParty contained rewrite_handler_code +syn keyword ngxDirectiveThirdParty contained access_handler_type +syn keyword ngxDirectiveThirdParty contained access_handler_name +syn keyword ngxDirectiveThirdParty contained access_handler_code +syn keyword ngxDirectiveThirdParty contained header_filter_type +syn keyword ngxDirectiveThirdParty contained header_filter_name +syn keyword ngxDirectiveThirdParty contained header_filter_code +syn keyword ngxDirectiveThirdParty contained content_handler_property +syn keyword ngxDirectiveThirdParty contained rewrite_handler_property +syn keyword ngxDirectiveThirdParty contained access_handler_property +syn keyword ngxDirectiveThirdParty contained header_filter_property +syn keyword ngxDirectiveThirdParty contained always_read_body +syn keyword ngxDirectiveThirdParty contained shared_map +syn keyword ngxDirectiveThirdParty contained write_page_size " Upstream Consistent Hash " A load balancer that uses an internal consistent hash ring to select the right backend node. -syn keyword ngxDirectiveThirdParty consistent_hash +syn keyword ngxDirectiveThirdParty contained consistent_hash " Nginx Development Kit " 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. " 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. -syn keyword ngxDirectiveThirdParty upstream_list +syn keyword ngxDirectiveThirdParty contained upstream_list " Drizzle Module " Upstream module for talking to MySQL and Drizzle directly -syn keyword ngxDirectiveThirdParty drizzle_server -syn keyword ngxDirectiveThirdParty drizzle_keepalive -syn keyword ngxDirectiveThirdParty drizzle_query -syn keyword ngxDirectiveThirdParty drizzle_pass -syn keyword ngxDirectiveThirdParty drizzle_connect_timeout -syn keyword ngxDirectiveThirdParty drizzle_send_query_timeout -syn keyword ngxDirectiveThirdParty drizzle_recv_cols_timeout -syn keyword ngxDirectiveThirdParty drizzle_recv_rows_timeout -syn keyword ngxDirectiveThirdParty drizzle_buffer_size -syn keyword ngxDirectiveThirdParty drizzle_module_header -syn keyword ngxDirectiveThirdParty drizzle_status +syn keyword ngxDirectiveThirdParty contained drizzle_server +syn keyword ngxDirectiveThirdParty contained drizzle_keepalive +syn keyword ngxDirectiveThirdParty contained drizzle_query +syn keyword ngxDirectiveThirdParty contained drizzle_pass +syn keyword ngxDirectiveThirdParty contained drizzle_connect_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_send_query_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_recv_cols_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_recv_rows_timeout +syn keyword ngxDirectiveThirdParty contained drizzle_buffer_size +syn keyword ngxDirectiveThirdParty contained drizzle_module_header +syn keyword ngxDirectiveThirdParty contained drizzle_status " Dynamic ETags Module " Attempt at handling ETag / If-None-Match on proxied content. -syn keyword ngxDirectiveThirdParty dynamic_etags +syn keyword ngxDirectiveThirdParty contained dynamic_etags " Echo Module " Bringing the power of "echo", "sleep", "time" and more to Nginx's config file -syn keyword ngxDirectiveThirdParty echo -syn keyword ngxDirectiveThirdParty echo_duplicate -syn keyword ngxDirectiveThirdParty echo_flush -syn keyword ngxDirectiveThirdParty echo_sleep -syn keyword ngxDirectiveThirdParty echo_blocking_sleep -syn keyword ngxDirectiveThirdParty echo_reset_timer -syn keyword ngxDirectiveThirdParty echo_read_request_body -syn keyword ngxDirectiveThirdParty echo_location_async -syn keyword ngxDirectiveThirdParty echo_location -syn keyword ngxDirectiveThirdParty echo_subrequest_async -syn keyword ngxDirectiveThirdParty echo_subrequest -syn keyword ngxDirectiveThirdParty echo_foreach_split -syn keyword ngxDirectiveThirdParty echo_end -syn keyword ngxDirectiveThirdParty echo_request_body -syn keyword ngxDirectiveThirdParty echo_exec -syn keyword ngxDirectiveThirdParty echo_status -syn keyword ngxDirectiveThirdParty echo_before_body -syn keyword ngxDirectiveThirdParty echo_after_body +syn keyword ngxDirectiveThirdParty contained echo +syn keyword ngxDirectiveThirdParty contained echo_duplicate +syn keyword ngxDirectiveThirdParty contained echo_flush +syn keyword ngxDirectiveThirdParty contained echo_sleep +syn keyword ngxDirectiveThirdParty contained echo_blocking_sleep +syn keyword ngxDirectiveThirdParty contained echo_reset_timer +syn keyword ngxDirectiveThirdParty contained echo_read_request_body +syn keyword ngxDirectiveThirdParty contained echo_location_async +syn keyword ngxDirectiveThirdParty contained echo_location +syn keyword ngxDirectiveThirdParty contained echo_subrequest_async +syn keyword ngxDirectiveThirdParty contained echo_subrequest +syn keyword ngxDirectiveThirdParty contained echo_foreach_split +syn keyword ngxDirectiveThirdParty contained echo_end +syn keyword ngxDirectiveThirdParty contained echo_request_body +syn keyword ngxDirectiveThirdParty contained echo_exec +syn keyword ngxDirectiveThirdParty contained echo_status +syn keyword ngxDirectiveThirdParty contained echo_before_body +syn keyword ngxDirectiveThirdParty contained echo_after_body " Encrypted Session Module " Encrypt and decrypt nginx variable values -syn keyword ngxDirectiveThirdParty encrypted_session_key -syn keyword ngxDirectiveThirdParty encrypted_session_iv -syn keyword ngxDirectiveThirdParty encrypted_session_expires -syn keyword ngxDirectiveThirdParty set_encrypt_session -syn keyword ngxDirectiveThirdParty set_decrypt_session +syn keyword ngxDirectiveThirdParty contained encrypted_session_key +syn keyword ngxDirectiveThirdParty contained encrypted_session_iv +syn keyword ngxDirectiveThirdParty contained encrypted_session_expires +syn keyword ngxDirectiveThirdParty contained set_encrypt_session +syn keyword ngxDirectiveThirdParty contained set_decrypt_session " Enhanced Memcached Module " This module is based on the standard Nginx Memcached module, with some additonal features -syn keyword ngxDirectiveThirdParty enhanced_memcached_pass -syn keyword ngxDirectiveThirdParty enhanced_memcached_hash_keys_with_md5 -syn keyword ngxDirectiveThirdParty enhanced_memcached_allow_put -syn keyword ngxDirectiveThirdParty enhanced_memcached_allow_delete -syn keyword ngxDirectiveThirdParty enhanced_memcached_stats -syn keyword ngxDirectiveThirdParty enhanced_memcached_flush -syn keyword ngxDirectiveThirdParty enhanced_memcached_flush_namespace -syn keyword ngxDirectiveThirdParty enhanced_memcached_bind -syn keyword ngxDirectiveThirdParty enhanced_memcached_connect_timeout -syn keyword ngxDirectiveThirdParty enhanced_memcached_send_timeout -syn keyword ngxDirectiveThirdParty enhanced_memcached_buffer_size -syn keyword ngxDirectiveThirdParty enhanced_memcached_read_timeout +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_pass +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_hash_keys_with_md5 +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_allow_put +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_allow_delete +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_stats +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_flush +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_flush_namespace +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_bind +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_connect_timeout +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_send_timeout +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_buffer_size +syn keyword ngxDirectiveThirdParty contained enhanced_memcached_read_timeout " Events Module (DEPRECATED) " Provides options for start/stop events. -syn keyword ngxDirectiveDeprecated on_start -syn keyword ngxDirectiveDeprecated on_stop +syn keyword ngxDirectiveDeprecated contained on_start +syn keyword ngxDirectiveDeprecated contained on_stop " EY Balancer Module " Adds a request queue to Nginx that allows the limiting of concurrent requests passed to the upstream. -syn keyword ngxDirectiveThirdParty max_connections -syn keyword ngxDirectiveThirdParty max_connections_max_queue_length -syn keyword ngxDirectiveThirdParty max_connections_queue_timeout +syn keyword ngxDirectiveThirdParty contained max_connections +syn keyword ngxDirectiveThirdParty contained max_connections_max_queue_length +syn keyword ngxDirectiveThirdParty contained max_connections_queue_timeout " Upstream Fair Balancer " Sends an incoming request to the least-busy backend server, rather than distributing requests round-robin. -syn keyword ngxDirectiveThirdParty fair -syn keyword ngxDirectiveThirdParty upstream_fair_shm_size +syn keyword ngxDirectiveThirdParty contained fair +syn keyword ngxDirectiveThirdParty contained upstream_fair_shm_size " Fancy Indexes Module " Like the built-in autoindex module, but fancier. -syn keyword ngxDirectiveThirdParty fancyindex -syn keyword ngxDirectiveThirdParty fancyindex_default_sort -syn keyword ngxDirectiveThirdParty fancyindex_directories_first -syn keyword ngxDirectiveThirdParty fancyindex_css_href -syn keyword ngxDirectiveThirdParty fancyindex_exact_size -syn keyword ngxDirectiveThirdParty fancyindex_name_length -syn keyword ngxDirectiveThirdParty fancyindex_footer -syn keyword ngxDirectiveThirdParty fancyindex_header -syn keyword ngxDirectiveThirdParty fancyindex_show_path -syn keyword ngxDirectiveThirdParty fancyindex_ignore -syn keyword ngxDirectiveThirdParty fancyindex_hide_symlinks -syn keyword ngxDirectiveThirdParty fancyindex_localtime -syn keyword ngxDirectiveThirdParty fancyindex_time_format +syn keyword ngxDirectiveThirdParty contained fancyindex +syn keyword ngxDirectiveThirdParty contained fancyindex_default_sort +syn keyword ngxDirectiveThirdParty contained fancyindex_directories_first +syn keyword ngxDirectiveThirdParty contained fancyindex_css_href +syn keyword ngxDirectiveThirdParty contained fancyindex_exact_size +syn keyword ngxDirectiveThirdParty contained fancyindex_name_length +syn keyword ngxDirectiveThirdParty contained fancyindex_footer +syn keyword ngxDirectiveThirdParty contained fancyindex_header +syn keyword ngxDirectiveThirdParty contained fancyindex_show_path +syn keyword ngxDirectiveThirdParty contained fancyindex_ignore +syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks +syn keyword ngxDirectiveThirdParty contained fancyindex_localtime +syn keyword ngxDirectiveThirdParty contained fancyindex_time_format " Form Auth Module " Provides authentication and authorization with credentials submitted via POST request -syn keyword ngxDirectiveThirdParty form_auth -syn keyword ngxDirectiveThirdParty form_auth_pam_service -syn keyword ngxDirectiveThirdParty form_auth_login -syn keyword ngxDirectiveThirdParty form_auth_password -syn keyword ngxDirectiveThirdParty form_auth_remote_user +syn keyword ngxDirectiveThirdParty contained form_auth +syn keyword ngxDirectiveThirdParty contained form_auth_pam_service +syn keyword ngxDirectiveThirdParty contained form_auth_login +syn keyword ngxDirectiveThirdParty contained form_auth_password +syn keyword ngxDirectiveThirdParty contained form_auth_remote_user " Form Input Module " Reads HTTP POST and PUT request body encoded in "application/x-www-form-urlencoded" and parses the arguments into nginx variables. -syn keyword ngxDirectiveThirdParty set_form_input -syn keyword ngxDirectiveThirdParty set_form_input_multi +syn keyword ngxDirectiveThirdParty contained set_form_input +syn keyword ngxDirectiveThirdParty contained set_form_input_multi " GeoIP Module (DEPRECATED) " Country code lookups via the MaxMind GeoIP API. -syn keyword ngxDirectiveDeprecated geoip_country_file +syn keyword ngxDirectiveDeprecated contained geoip_country_file " GeoIP 2 Module " Creates variables with values from the maxmind geoip2 databases based on the client IP -syn keyword ngxDirectiveThirdParty geoip2 +syn keyword ngxDirectiveThirdParty contained geoip2 " GridFS Module " Nginx module for serving files from MongoDB's GridFS -syn keyword ngxDirectiveThirdParty gridfs +syn keyword ngxDirectiveThirdParty contained gridfs " Headers More Module " Set and clear input and output headers...more than "add"! -syn keyword ngxDirectiveThirdParty more_clear_headers -syn keyword ngxDirectiveThirdParty more_clear_input_headers -syn keyword ngxDirectiveThirdParty more_set_headers -syn keyword ngxDirectiveThirdParty more_set_input_headers +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 " Health Checks Upstreams Module " Polls backends and if they respond with HTTP 200 + an optional request body, they are marked good. Otherwise, they are marked bad. -syn keyword ngxDirectiveThirdParty healthcheck_enabled -syn keyword ngxDirectiveThirdParty healthcheck_delay -syn keyword ngxDirectiveThirdParty healthcheck_timeout -syn keyword ngxDirectiveThirdParty healthcheck_failcount -syn keyword ngxDirectiveThirdParty healthcheck_send -syn keyword ngxDirectiveThirdParty healthcheck_expected -syn keyword ngxDirectiveThirdParty healthcheck_buffer -syn keyword ngxDirectiveThirdParty healthcheck_status +syn keyword ngxDirectiveThirdParty contained healthcheck_enabled +syn keyword ngxDirectiveThirdParty contained healthcheck_delay +syn keyword ngxDirectiveThirdParty contained healthcheck_timeout +syn keyword ngxDirectiveThirdParty contained healthcheck_failcount +syn keyword ngxDirectiveThirdParty contained healthcheck_send +syn keyword ngxDirectiveThirdParty contained healthcheck_expected +syn keyword ngxDirectiveThirdParty contained healthcheck_buffer +syn keyword ngxDirectiveThirdParty contained healthcheck_status " HTTP Accounting Module " Add traffic stat function to nginx. Useful for http accounting based on nginx configuration logic -syn keyword ngxDirectiveThirdParty http_accounting -syn keyword ngxDirectiveThirdParty http_accounting_log -syn keyword ngxDirectiveThirdParty http_accounting_id -syn keyword ngxDirectiveThirdParty http_accounting_interval -syn keyword ngxDirectiveThirdParty http_accounting_perturb +syn keyword ngxDirectiveThirdParty contained http_accounting +syn keyword ngxDirectiveThirdParty contained http_accounting_log +syn keyword ngxDirectiveThirdParty contained http_accounting_id +syn keyword ngxDirectiveThirdParty contained http_accounting_interval +syn keyword ngxDirectiveThirdParty contained http_accounting_perturb " Nginx Digest Authentication module " Digest Authentication for Nginx -syn keyword ngxDirectiveThirdParty auth_digest -syn keyword ngxDirectiveThirdParty auth_digest_user_file -syn keyword ngxDirectiveThirdParty auth_digest_timeout -syn keyword ngxDirectiveThirdParty auth_digest_expires -syn keyword ngxDirectiveThirdParty auth_digest_replays -syn keyword ngxDirectiveThirdParty auth_digest_shm_size +syn keyword ngxDirectiveThirdParty contained auth_digest +syn keyword ngxDirectiveThirdParty contained auth_digest_user_file +syn keyword ngxDirectiveThirdParty contained auth_digest_timeout +syn keyword ngxDirectiveThirdParty contained auth_digest_expires +syn keyword ngxDirectiveThirdParty contained auth_digest_replays +syn keyword ngxDirectiveThirdParty contained auth_digest_shm_size " Auth PAM Module " HTTP Basic Authentication using PAM. -syn keyword ngxDirectiveThirdParty auth_pam -syn keyword ngxDirectiveThirdParty auth_pam_service_name +syn keyword ngxDirectiveThirdParty contained auth_pam +syn keyword ngxDirectiveThirdParty contained auth_pam_service_name " HTTP Auth Request Module " Implements client authorization based on the result of a subrequest -" syn keyword ngxDirectiveThirdParty auth_request -" syn keyword ngxDirectiveThirdParty auth_request_set +" syn keyword ngxDirectiveThirdParty contained auth_request +" syn keyword ngxDirectiveThirdParty contained auth_request_set " HTTP Concatenation module for Nginx " A Nginx module for concatenating files in a given context: CSS and JS files usually -syn keyword ngxDirectiveThirdParty concat -syn keyword ngxDirectiveThirdParty concat_types -syn keyword ngxDirectiveThirdParty concat_unique -syn keyword ngxDirectiveThirdParty concat_max_files -syn keyword ngxDirectiveThirdParty concat_delimiter -syn keyword ngxDirectiveThirdParty concat_ignore_file_error +syn keyword ngxDirectiveThirdParty contained concat +syn keyword ngxDirectiveThirdParty contained concat_types +syn keyword ngxDirectiveThirdParty contained concat_unique +syn keyword ngxDirectiveThirdParty contained concat_max_files +syn keyword ngxDirectiveThirdParty contained concat_delimiter +syn keyword ngxDirectiveThirdParty contained concat_ignore_file_error " HTTP Dynamic Upstream Module " Update upstreams' config by restful interface -syn keyword ngxDirectiveThirdParty dyups_interface -syn keyword ngxDirectiveThirdParty dyups_read_msg_timeout -syn keyword ngxDirectiveThirdParty dyups_shm_zone_size -syn keyword ngxDirectiveThirdParty dyups_upstream_conf -syn keyword ngxDirectiveThirdParty dyups_trylock +syn keyword ngxDirectiveThirdParty contained dyups_interface +syn keyword ngxDirectiveThirdParty contained dyups_read_msg_timeout +syn keyword ngxDirectiveThirdParty contained dyups_shm_zone_size +syn keyword ngxDirectiveThirdParty contained dyups_upstream_conf +syn keyword ngxDirectiveThirdParty contained dyups_trylock " HTTP Footer If Filter Module " The ngx_http_footer_if_filter_module is used to add given content to the end of the response according to the condition specified. -syn keyword ngxDirectiveThirdParty footer_if +syn keyword ngxDirectiveThirdParty contained footer_if " HTTP Footer Filter Module " This module implements a body filter that adds a given string to the page footer. -syn keyword ngxDirectiveThirdParty footer -syn keyword ngxDirectiveThirdParty footer_types +syn keyword ngxDirectiveThirdParty contained footer +syn keyword ngxDirectiveThirdParty contained footer_types " HTTP Internal Redirect Module " Make an internal redirect to the uri specified according to the condition specified. -syn keyword ngxDirectiveThirdParty internal_redirect_if -syn keyword ngxDirectiveThirdParty internal_redirect_if_no_postponed +syn keyword ngxDirectiveThirdParty contained internal_redirect_if +syn keyword ngxDirectiveThirdParty contained internal_redirect_if_no_postponed " HTTP JavaScript Module " Embedding SpiderMonkey. Nearly full port on Perl module. -syn keyword ngxDirectiveThirdParty js -syn keyword ngxDirectiveThirdParty js_filter -syn keyword ngxDirectiveThirdParty js_filter_types -syn keyword ngxDirectiveThirdParty js_load -syn keyword ngxDirectiveThirdParty js_maxmem -syn keyword ngxDirectiveThirdParty js_require -syn keyword ngxDirectiveThirdParty js_set -syn keyword ngxDirectiveThirdParty js_utf8 +syn keyword ngxDirectiveThirdParty contained js +syn keyword ngxDirectiveThirdParty contained js_filter +syn keyword ngxDirectiveThirdParty contained js_filter_types +syn keyword ngxDirectiveThirdParty contained js_load +syn keyword ngxDirectiveThirdParty contained js_maxmem +syn keyword ngxDirectiveThirdParty contained js_require +syn keyword ngxDirectiveThirdParty contained js_set +syn keyword ngxDirectiveThirdParty contained js_utf8 " HTTP Push Module (DEPRECATED) " Turn Nginx into an adept long-polling HTTP Push (Comet) server. -syn keyword ngxDirectiveDeprecated push_buffer_size -syn keyword ngxDirectiveDeprecated push_listener -syn keyword ngxDirectiveDeprecated push_message_timeout -syn keyword ngxDirectiveDeprecated push_queue_messages -syn keyword ngxDirectiveDeprecated push_sender +syn keyword ngxDirectiveDeprecated contained push_buffer_size +syn keyword ngxDirectiveDeprecated contained push_listener +syn keyword ngxDirectiveDeprecated contained push_message_timeout +syn keyword ngxDirectiveDeprecated contained push_queue_messages +syn keyword ngxDirectiveDeprecated contained push_sender " HTTP Redis Module " Redis support. -syn keyword ngxDirectiveThirdParty redis_bind -syn keyword ngxDirectiveThirdParty redis_buffer_size -syn keyword ngxDirectiveThirdParty redis_connect_timeout -syn keyword ngxDirectiveThirdParty redis_next_upstream -syn keyword ngxDirectiveThirdParty redis_pass -syn keyword ngxDirectiveThirdParty redis_read_timeout -syn keyword ngxDirectiveThirdParty redis_send_timeout +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_next_upstream +syn keyword ngxDirectiveThirdParty contained redis_pass +syn keyword ngxDirectiveThirdParty contained redis_read_timeout +syn keyword ngxDirectiveThirdParty contained redis_send_timeout " Iconv Module " A character conversion nginx module using libiconv -syn keyword ngxDirectiveThirdParty set_iconv -syn keyword ngxDirectiveThirdParty iconv_buffer_size -syn keyword ngxDirectiveThirdParty iconv_filter +syn keyword ngxDirectiveThirdParty contained set_iconv +syn keyword ngxDirectiveThirdParty contained iconv_buffer_size +syn keyword ngxDirectiveThirdParty contained iconv_filter " IP Blocker Module " An efficient shared memory IP blocking system for nginx. -syn keyword ngxDirectiveThirdParty ip_blocker +syn keyword ngxDirectiveThirdParty contained ip_blocker " IP2Location Module " Allows user to lookup for geolocation information using IP2Location database -syn keyword ngxDirectiveThirdParty ip2location_database +syn keyword ngxDirectiveThirdParty contained ip2location_database " JS Module " Reflect the nginx functionality in JS -syn keyword ngxDirectiveThirdParty js -syn keyword ngxDirectiveThirdParty js_access -syn keyword ngxDirectiveThirdParty js_load -syn keyword ngxDirectiveThirdParty js_set +syn keyword ngxDirectiveThirdParty contained js +syn keyword ngxDirectiveThirdParty contained js_access +syn keyword ngxDirectiveThirdParty contained js_load +syn keyword ngxDirectiveThirdParty contained js_set " Limit Upload Rate Module " Limit client-upload rate when they are sending request bodies to you -syn keyword ngxDirectiveThirdParty limit_upload_rate -syn keyword ngxDirectiveThirdParty limit_upload_rate_after +syn keyword ngxDirectiveThirdParty contained limit_upload_rate +syn keyword ngxDirectiveThirdParty contained limit_upload_rate_after " Limit Upstream Module " Limit the number of connections to upstream for NGINX -syn keyword ngxDirectiveThirdParty limit_upstream_zone -syn keyword ngxDirectiveThirdParty limit_upstream_conn -syn keyword ngxDirectiveThirdParty limit_upstream_log_level +syn keyword ngxDirectiveThirdParty contained limit_upstream_zone +syn keyword ngxDirectiveThirdParty contained limit_upstream_conn +syn keyword ngxDirectiveThirdParty contained limit_upstream_log_level " Log If Module " Conditional accesslog for nginx -syn keyword ngxDirectiveThirdParty access_log_bypass_if +syn keyword ngxDirectiveThirdParty contained access_log_bypass_if " Log Request Speed (DEPRECATED) " Log the time it took to process each request. -syn keyword ngxDirectiveDeprecated log_request_speed_filter -syn keyword ngxDirectiveDeprecated log_request_speed_filter_timeout +syn keyword ngxDirectiveDeprecated contained log_request_speed_filter +syn keyword ngxDirectiveDeprecated contained log_request_speed_filter_timeout " Log ZeroMQ Module " ZeroMQ logger module for nginx -syn keyword ngxDirectiveThirdParty log_zmq_server -syn keyword ngxDirectiveThirdParty log_zmq_endpoint -syn keyword ngxDirectiveThirdParty log_zmq_format -syn keyword ngxDirectiveThirdParty log_zmq_off +syn keyword ngxDirectiveThirdParty contained log_zmq_server +syn keyword ngxDirectiveThirdParty contained log_zmq_endpoint +syn keyword ngxDirectiveThirdParty contained log_zmq_format +syn keyword ngxDirectiveThirdParty contained log_zmq_off " Lower/UpperCase Module " This module simply uppercases or lowercases a string and saves it into a new variable. -syn keyword ngxDirectiveThirdParty lower -syn keyword ngxDirectiveThirdParty upper +syn keyword ngxDirectiveThirdParty contained lower +syn keyword ngxDirectiveThirdParty contained upper " Lua Upstream Module " Nginx C module to expose Lua API to ngx_lua for Nginx upstreams " Lua Module " Embed the Power of Lua into NGINX HTTP servers -syn keyword ngxDirectiveThirdParty lua_use_default_type -syn keyword ngxDirectiveThirdParty lua_malloc_trim -syn keyword ngxDirectiveThirdParty lua_code_cache -syn keyword ngxDirectiveThirdParty lua_regex_cache_max_entries -syn keyword ngxDirectiveThirdParty lua_regex_match_limit -syn keyword ngxDirectiveThirdParty lua_package_path -syn keyword ngxDirectiveThirdParty lua_package_cpath -syn keyword ngxDirectiveThirdParty init_by_lua -syn keyword ngxDirectiveThirdParty init_by_lua_block -syn keyword ngxDirectiveThirdParty init_by_lua_file -syn keyword ngxDirectiveThirdParty init_worker_by_lua -syn keyword ngxDirectiveThirdParty init_worker_by_lua_block -syn keyword ngxDirectiveThirdParty init_worker_by_lua_file -syn keyword ngxDirectiveThirdParty set_by_lua -syn keyword ngxDirectiveThirdParty set_by_lua_block -syn keyword ngxDirectiveThirdParty set_by_lua_file -syn keyword ngxDirectiveThirdParty content_by_lua -syn keyword ngxDirectiveThirdParty content_by_lua_block -syn keyword ngxDirectiveThirdParty content_by_lua_file -syn keyword ngxDirectiveThirdParty rewrite_by_lua -syn keyword ngxDirectiveThirdParty rewrite_by_lua_block -syn keyword ngxDirectiveThirdParty rewrite_by_lua_file -syn keyword ngxDirectiveThirdParty access_by_lua -syn keyword ngxDirectiveThirdParty access_by_lua_block -syn keyword ngxDirectiveThirdParty access_by_lua_file -syn keyword ngxDirectiveThirdParty header_filter_by_lua -syn keyword ngxDirectiveThirdParty header_filter_by_lua_block -syn keyword ngxDirectiveThirdParty header_filter_by_lua_file -syn keyword ngxDirectiveThirdParty body_filter_by_lua -syn keyword ngxDirectiveThirdParty body_filter_by_lua_block -syn keyword ngxDirectiveThirdParty body_filter_by_lua_file -syn keyword ngxDirectiveThirdParty log_by_lua -syn keyword ngxDirectiveThirdParty log_by_lua_block -syn keyword ngxDirectiveThirdParty log_by_lua_file -syn keyword ngxDirectiveThirdParty balancer_by_lua_block -syn keyword ngxDirectiveThirdParty balancer_by_lua_file -syn keyword ngxDirectiveThirdParty lua_need_request_body -syn keyword ngxDirectiveThirdParty ssl_certificate_by_lua_block -syn keyword ngxDirectiveThirdParty ssl_certificate_by_lua_file -syn keyword ngxDirectiveThirdParty ssl_session_fetch_by_lua_block -syn keyword ngxDirectiveThirdParty ssl_session_fetch_by_lua_file -syn keyword ngxDirectiveThirdParty ssl_session_store_by_lua_block -syn keyword ngxDirectiveThirdParty ssl_session_store_by_lua_file -syn keyword ngxDirectiveThirdParty lua_shared_dict -syn keyword ngxDirectiveThirdParty lua_socket_connect_timeout -syn keyword ngxDirectiveThirdParty lua_socket_send_timeout -syn keyword ngxDirectiveThirdParty lua_socket_send_lowat -syn keyword ngxDirectiveThirdParty lua_socket_read_timeout -syn keyword ngxDirectiveThirdParty lua_socket_buffer_size -syn keyword ngxDirectiveThirdParty lua_socket_pool_size -syn keyword ngxDirectiveThirdParty lua_socket_keepalive_timeout -syn keyword ngxDirectiveThirdParty lua_socket_log_errors -syn keyword ngxDirectiveThirdParty lua_ssl_ciphers -syn keyword ngxDirectiveThirdParty lua_ssl_crl -syn keyword ngxDirectiveThirdParty lua_ssl_protocols -syn keyword ngxDirectiveThirdParty lua_ssl_trusted_certificate -syn keyword ngxDirectiveThirdParty lua_ssl_verify_depth -syn keyword ngxDirectiveThirdParty lua_http10_buffering -syn keyword ngxDirectiveThirdParty rewrite_by_lua_no_postpone -syn keyword ngxDirectiveThirdParty access_by_lua_no_postpone -syn keyword ngxDirectiveThirdParty lua_transform_underscores_in_response_headers -syn keyword ngxDirectiveThirdParty lua_check_client_abort -syn keyword ngxDirectiveThirdParty lua_max_pending_timers -syn keyword ngxDirectiveThirdParty lua_max_running_timers +syn keyword ngxDirectiveThirdParty contained lua_use_default_type +syn keyword ngxDirectiveThirdParty contained lua_malloc_trim +syn keyword ngxDirectiveThirdParty contained lua_code_cache +syn keyword ngxDirectiveThirdParty contained lua_regex_cache_max_entries +syn keyword ngxDirectiveThirdParty contained lua_regex_match_limit +syn keyword ngxDirectiveThirdParty contained lua_package_path +syn keyword ngxDirectiveThirdParty contained lua_package_cpath +syn keyword ngxDirectiveThirdParty contained init_by_lua +syn keyword ngxDirectiveThirdParty contained init_by_lua_block +syn keyword ngxDirectiveThirdParty contained init_by_lua_file +syn keyword ngxDirectiveThirdParty contained init_worker_by_lua +syn keyword ngxDirectiveThirdParty contained init_worker_by_lua_block +syn keyword ngxDirectiveThirdParty contained init_worker_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 +syn keyword ngxDirectiveThirdParty contained content_by_lua +syn keyword ngxDirectiveThirdParty contained content_by_lua_block +syn keyword ngxDirectiveThirdParty contained content_by_lua_file +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 access_by_lua +syn keyword ngxDirectiveThirdParty contained access_by_lua_block +syn keyword ngxDirectiveThirdParty contained access_by_lua_file +syn keyword ngxDirectiveThirdParty contained header_filter_by_lua +syn keyword ngxDirectiveThirdParty contained header_filter_by_lua_block +syn keyword ngxDirectiveThirdParty contained header_filter_by_lua_file +syn keyword ngxDirectiveThirdParty contained body_filter_by_lua +syn keyword ngxDirectiveThirdParty contained body_filter_by_lua_block +syn keyword ngxDirectiveThirdParty contained body_filter_by_lua_file +syn keyword ngxDirectiveThirdParty contained log_by_lua +syn keyword ngxDirectiveThirdParty contained log_by_lua_block +syn keyword ngxDirectiveThirdParty contained log_by_lua_file +syn keyword ngxDirectiveThirdParty contained balancer_by_lua_block +syn keyword ngxDirectiveThirdParty contained balancer_by_lua_file +syn keyword ngxDirectiveThirdParty contained lua_need_request_body +syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_block +syn keyword ngxDirectiveThirdParty contained ssl_certificate_by_lua_file +syn keyword ngxDirectiveThirdParty contained ssl_session_fetch_by_lua_block +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 +syn keyword ngxDirectiveThirdParty contained lua_shared_dict +syn keyword ngxDirectiveThirdParty contained lua_socket_connect_timeout +syn keyword ngxDirectiveThirdParty contained lua_socket_send_timeout +syn keyword ngxDirectiveThirdParty contained lua_socket_send_lowat +syn keyword ngxDirectiveThirdParty contained lua_socket_read_timeout +syn keyword ngxDirectiveThirdParty contained lua_socket_buffer_size +syn keyword ngxDirectiveThirdParty contained lua_socket_pool_size +syn keyword ngxDirectiveThirdParty contained lua_socket_keepalive_timeout +syn keyword ngxDirectiveThirdParty contained lua_socket_log_errors +syn keyword ngxDirectiveThirdParty contained lua_ssl_ciphers +syn keyword ngxDirectiveThirdParty contained lua_ssl_crl +syn keyword ngxDirectiveThirdParty contained lua_ssl_protocols +syn keyword ngxDirectiveThirdParty contained lua_ssl_trusted_certificate +syn keyword ngxDirectiveThirdParty contained lua_ssl_verify_depth +syn keyword ngxDirectiveThirdParty contained lua_http10_buffering +syn keyword ngxDirectiveThirdParty contained rewrite_by_lua_no_postpone +syn keyword ngxDirectiveThirdParty contained access_by_lua_no_postpone +syn keyword ngxDirectiveThirdParty contained lua_transform_underscores_in_response_headers +syn keyword ngxDirectiveThirdParty contained lua_check_client_abort +syn keyword ngxDirectiveThirdParty contained lua_max_pending_timers +syn keyword ngxDirectiveThirdParty contained lua_max_running_timers " MD5 Filter Module " A content filter for nginx, which returns the md5 hash of the content otherwise returned. -syn keyword ngxDirectiveThirdParty md5_filter +syn keyword ngxDirectiveThirdParty contained md5_filter " Memc Module " An extended version of the standard memcached module that supports set, add, delete, and many more memcached commands. -syn keyword ngxDirectiveThirdParty memc_buffer_size -syn keyword ngxDirectiveThirdParty memc_cmds_allowed -syn keyword ngxDirectiveThirdParty memc_connect_timeout -syn keyword ngxDirectiveThirdParty memc_flags_to_last_modified -syn keyword ngxDirectiveThirdParty memc_next_upstream -syn keyword ngxDirectiveThirdParty memc_pass -syn keyword ngxDirectiveThirdParty memc_read_timeout -syn keyword ngxDirectiveThirdParty memc_send_timeout -syn keyword ngxDirectiveThirdParty memc_upstream_fail_timeout -syn keyword ngxDirectiveThirdParty memc_upstream_max_fails +syn keyword ngxDirectiveThirdParty contained memc_buffer_size +syn keyword ngxDirectiveThirdParty contained memc_cmds_allowed +syn keyword ngxDirectiveThirdParty contained memc_connect_timeout +syn keyword ngxDirectiveThirdParty contained memc_flags_to_last_modified +syn keyword ngxDirectiveThirdParty contained memc_next_upstream +syn keyword ngxDirectiveThirdParty contained memc_pass +syn keyword ngxDirectiveThirdParty contained memc_read_timeout +syn keyword ngxDirectiveThirdParty contained memc_send_timeout +syn keyword ngxDirectiveThirdParty contained memc_upstream_fail_timeout +syn keyword ngxDirectiveThirdParty contained memc_upstream_max_fails " Mod Security Module " ModSecurity is an open source, cross platform web application firewall (WAF) engine -syn keyword ngxDirectiveThirdParty ModSecurityConfig -syn keyword ngxDirectiveThirdParty ModSecurityEnabled -syn keyword ngxDirectiveThirdParty pool_context -syn keyword ngxDirectiveThirdParty pool_context_hash_size +syn keyword ngxDirectiveThirdParty contained ModSecurityConfig +syn keyword ngxDirectiveThirdParty contained ModSecurityEnabled +syn keyword ngxDirectiveThirdParty contained pool_context +syn keyword ngxDirectiveThirdParty contained pool_context_hash_size " Mogilefs Module " MogileFS client for nginx web server. -syn keyword ngxDirectiveThirdParty mogilefs_pass -syn keyword ngxDirectiveThirdParty mogilefs_methods -syn keyword ngxDirectiveThirdParty mogilefs_domain -syn keyword ngxDirectiveThirdParty mogilefs_class -syn keyword ngxDirectiveThirdParty mogilefs_tracker -syn keyword ngxDirectiveThirdParty mogilefs_noverify -syn keyword ngxDirectiveThirdParty mogilefs_connect_timeout -syn keyword ngxDirectiveThirdParty mogilefs_send_timeout -syn keyword ngxDirectiveThirdParty mogilefs_read_timeout +syn keyword ngxDirectiveThirdParty contained mogilefs_pass +syn keyword ngxDirectiveThirdParty contained mogilefs_methods +syn keyword ngxDirectiveThirdParty contained mogilefs_domain +syn keyword ngxDirectiveThirdParty contained mogilefs_class +syn keyword ngxDirectiveThirdParty contained mogilefs_tracker +syn keyword ngxDirectiveThirdParty contained mogilefs_noverify +syn keyword ngxDirectiveThirdParty contained mogilefs_connect_timeout +syn keyword ngxDirectiveThirdParty contained mogilefs_send_timeout +syn keyword ngxDirectiveThirdParty contained mogilefs_read_timeout " Mongo Module " Upstream module that allows nginx to communicate directly with MongoDB database. -syn keyword ngxDirectiveThirdParty mongo_auth -syn keyword ngxDirectiveThirdParty mongo_pass -syn keyword ngxDirectiveThirdParty mongo_query -syn keyword ngxDirectiveThirdParty mongo_json -syn keyword ngxDirectiveThirdParty mongo_bind -syn keyword ngxDirectiveThirdParty mongo_connect_timeout -syn keyword ngxDirectiveThirdParty mongo_send_timeout -syn keyword ngxDirectiveThirdParty mongo_read_timeout -syn keyword ngxDirectiveThirdParty mongo_buffering -syn keyword ngxDirectiveThirdParty mongo_buffer_size -syn keyword ngxDirectiveThirdParty mongo_buffers -syn keyword ngxDirectiveThirdParty mongo_busy_buffers_size -syn keyword ngxDirectiveThirdParty mongo_next_upstream +syn keyword ngxDirectiveThirdParty contained mongo_auth +syn keyword ngxDirectiveThirdParty contained mongo_pass +syn keyword ngxDirectiveThirdParty contained mongo_query +syn keyword ngxDirectiveThirdParty contained mongo_json +syn keyword ngxDirectiveThirdParty contained mongo_bind +syn keyword ngxDirectiveThirdParty contained mongo_connect_timeout +syn keyword ngxDirectiveThirdParty contained mongo_send_timeout +syn keyword ngxDirectiveThirdParty contained mongo_read_timeout +syn keyword ngxDirectiveThirdParty contained mongo_buffering +syn keyword ngxDirectiveThirdParty contained mongo_buffer_size +syn keyword ngxDirectiveThirdParty contained mongo_buffers +syn keyword ngxDirectiveThirdParty contained mongo_busy_buffers_size +syn keyword ngxDirectiveThirdParty contained mongo_next_upstream " MP4 Streaming Lite Module " Will seek to a certain time within H.264/MP4 files when provided with a 'start' parameter in the URL. -" syn keyword ngxDirectiveThirdParty mp4 +" syn keyword ngxDirectiveThirdParty contained mp4 " NAXSI Module " NAXSI is an open-source, high performance, low rules maintenance WAF for NGINX -syn keyword ngxDirectiveThirdParty DeniedUrl denied_url -syn keyword ngxDirectiveThirdParty LearningMode learning_mode -syn keyword ngxDirectiveThirdParty SecRulesEnabled rules_enabled -syn keyword ngxDirectiveThirdParty SecRulesDisabled rules_disabled -syn keyword ngxDirectiveThirdParty CheckRule check_rule -syn keyword ngxDirectiveThirdParty BasicRule basic_rule -syn keyword ngxDirectiveThirdParty MainRule main_rule -syn keyword ngxDirectiveThirdParty LibInjectionSql libinjection_sql -syn keyword ngxDirectiveThirdParty LibInjectionXss libinjection_xss +syn keyword ngxDirectiveThirdParty contained DeniedUrl denied_url +syn keyword ngxDirectiveThirdParty contained LearningMode learning_mode +syn keyword ngxDirectiveThirdParty contained SecRulesEnabled rules_enabled +syn keyword ngxDirectiveThirdParty contained SecRulesDisabled rules_disabled +syn keyword ngxDirectiveThirdParty contained CheckRule check_rule +syn keyword ngxDirectiveThirdParty contained BasicRule basic_rule +syn keyword ngxDirectiveThirdParty contained MainRule main_rule +syn keyword ngxDirectiveThirdParty contained LibInjectionSql libinjection_sql +syn keyword ngxDirectiveThirdParty contained LibInjectionXss libinjection_xss " Nchan Module " Fast, horizontally scalable, multiprocess pub/sub queuing server and proxy for HTTP, long-polling, Websockets and EventSource (SSE) -syn keyword ngxDirectiveThirdParty nchan_channel_id -syn keyword ngxDirectiveThirdParty nchan_channel_id_split_delimiter -syn keyword ngxDirectiveThirdParty nchan_eventsource_event -syn keyword ngxDirectiveThirdParty nchan_longpoll_multipart_response -syn keyword ngxDirectiveThirdParty nchan_publisher -syn keyword ngxDirectiveThirdParty nchan_publisher_channel_id -syn keyword ngxDirectiveThirdParty nchan_publisher_upstream_request -syn keyword ngxDirectiveThirdParty nchan_pubsub -syn keyword ngxDirectiveThirdParty nchan_subscribe_request -syn keyword ngxDirectiveThirdParty nchan_subscriber -syn keyword ngxDirectiveThirdParty nchan_subscriber_channel_id -syn keyword ngxDirectiveThirdParty nchan_subscriber_compound_etag_message_id -syn keyword ngxDirectiveThirdParty nchan_subscriber_first_message -syn keyword ngxDirectiveThirdParty nchan_subscriber_http_raw_stream_separator -syn keyword ngxDirectiveThirdParty nchan_subscriber_last_message_id -syn keyword ngxDirectiveThirdParty nchan_subscriber_message_id_custom_etag_header -syn keyword ngxDirectiveThirdParty nchan_subscriber_timeout -syn keyword ngxDirectiveThirdParty nchan_unsubscribe_request -syn keyword ngxDirectiveThirdParty nchan_websocket_ping_interval -syn keyword ngxDirectiveThirdParty nchan_authorize_request -syn keyword ngxDirectiveThirdParty nchan_max_reserved_memory -syn keyword ngxDirectiveThirdParty nchan_message_buffer_length -syn keyword ngxDirectiveThirdParty nchan_message_timeout -syn keyword ngxDirectiveThirdParty nchan_redis_idle_channel_cache_timeout -syn keyword ngxDirectiveThirdParty nchan_redis_namespace -syn keyword ngxDirectiveThirdParty nchan_redis_pass -syn keyword ngxDirectiveThirdParty nchan_redis_ping_interval -syn keyword ngxDirectiveThirdParty nchan_redis_server -syn keyword ngxDirectiveThirdParty nchan_redis_storage_mode -syn keyword ngxDirectiveThirdParty nchan_redis_url -syn keyword ngxDirectiveThirdParty nchan_store_messages -syn keyword ngxDirectiveThirdParty nchan_use_redis -syn keyword ngxDirectiveThirdParty nchan_access_control_allow_origin -syn keyword ngxDirectiveThirdParty nchan_channel_group -syn keyword ngxDirectiveThirdParty nchan_channel_group_accounting -syn keyword ngxDirectiveThirdParty nchan_group_location -syn keyword ngxDirectiveThirdParty nchan_group_max_channels -syn keyword ngxDirectiveThirdParty nchan_group_max_messages -syn keyword ngxDirectiveThirdParty nchan_group_max_messages_disk -syn keyword ngxDirectiveThirdParty nchan_group_max_messages_memory -syn keyword ngxDirectiveThirdParty nchan_group_max_subscribers -syn keyword ngxDirectiveThirdParty nchan_subscribe_existing_channels_only -syn keyword ngxDirectiveThirdParty nchan_channel_event_string -syn keyword ngxDirectiveThirdParty nchan_channel_events_channel_id -syn keyword ngxDirectiveThirdParty nchan_stub_status -syn keyword ngxDirectiveThirdParty nchan_max_channel_id_length -syn keyword ngxDirectiveThirdParty nchan_max_channel_subscribers -syn keyword ngxDirectiveThirdParty nchan_channel_timeout -syn keyword ngxDirectiveThirdParty nchan_storage_engine +syn keyword ngxDirectiveThirdParty contained nchan_channel_id +syn keyword ngxDirectiveThirdParty contained nchan_channel_id_split_delimiter +syn keyword ngxDirectiveThirdParty contained nchan_eventsource_event +syn keyword ngxDirectiveThirdParty contained nchan_longpoll_multipart_response +syn keyword ngxDirectiveThirdParty contained nchan_publisher +syn keyword ngxDirectiveThirdParty contained nchan_publisher_channel_id +syn keyword ngxDirectiveThirdParty contained nchan_publisher_upstream_request +syn keyword ngxDirectiveThirdParty contained nchan_pubsub +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_subscriber_first_message +syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator +syn keyword ngxDirectiveThirdParty contained nchan_subscriber_last_message_id +syn keyword ngxDirectiveThirdParty contained nchan_subscriber_message_id_custom_etag_header +syn keyword ngxDirectiveThirdParty contained nchan_subscriber_timeout +syn keyword ngxDirectiveThirdParty contained nchan_unsubscribe_request +syn keyword ngxDirectiveThirdParty contained nchan_websocket_ping_interval +syn keyword ngxDirectiveThirdParty contained nchan_authorize_request +syn keyword ngxDirectiveThirdParty contained nchan_max_reserved_memory +syn keyword ngxDirectiveThirdParty contained nchan_message_buffer_length +syn keyword ngxDirectiveThirdParty contained nchan_message_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout +syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace +syn keyword ngxDirectiveThirdParty contained nchan_redis_pass +syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval +syn keyword ngxDirectiveThirdParty contained nchan_redis_server +syn keyword ngxDirectiveThirdParty contained nchan_redis_storage_mode +syn keyword ngxDirectiveThirdParty contained nchan_redis_url +syn keyword ngxDirectiveThirdParty contained nchan_store_messages +syn keyword ngxDirectiveThirdParty contained nchan_use_redis +syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_origin +syn keyword ngxDirectiveThirdParty contained nchan_channel_group +syn keyword ngxDirectiveThirdParty contained nchan_channel_group_accounting +syn keyword ngxDirectiveThirdParty contained nchan_group_location +syn keyword ngxDirectiveThirdParty contained nchan_group_max_channels +syn keyword ngxDirectiveThirdParty contained nchan_group_max_messages +syn keyword ngxDirectiveThirdParty contained nchan_group_max_messages_disk +syn keyword ngxDirectiveThirdParty contained nchan_group_max_messages_memory +syn keyword ngxDirectiveThirdParty contained nchan_group_max_subscribers +syn keyword ngxDirectiveThirdParty contained nchan_subscribe_existing_channels_only +syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string +syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id +syn keyword ngxDirectiveThirdParty contained nchan_stub_status +syn keyword ngxDirectiveThirdParty contained nchan_max_channel_id_length +syn keyword ngxDirectiveThirdParty contained nchan_max_channel_subscribers +syn keyword ngxDirectiveThirdParty contained nchan_channel_timeout +syn keyword ngxDirectiveThirdParty contained nchan_storage_engine " Nginx Notice Module " Serve static file to POST requests. -syn keyword ngxDirectiveThirdParty notice -syn keyword ngxDirectiveThirdParty notice_type +syn keyword ngxDirectiveThirdParty contained notice +syn keyword ngxDirectiveThirdParty contained notice_type " OCSP Proxy Module " Nginx OCSP processing module designed for response caching -syn keyword ngxDirectiveThirdParty ocsp_proxy -syn keyword ngxDirectiveThirdParty ocsp_cache_timeout +syn keyword ngxDirectiveThirdParty contained ocsp_proxy +syn keyword ngxDirectiveThirdParty contained ocsp_cache_timeout " Eval Module " Module for nginx web server evaluates response of proxy or memcached module into variables. -syn keyword ngxDirectiveThirdParty eval -syn keyword ngxDirectiveThirdParty eval_escalate -syn keyword ngxDirectiveThirdParty eval_buffer_size -syn keyword ngxDirectiveThirdParty eval_override_content_type -syn keyword ngxDirectiveThirdParty eval_subrequest_in_memory +syn keyword ngxDirectiveThirdParty contained eval +syn keyword ngxDirectiveThirdParty contained eval_escalate +syn keyword ngxDirectiveThirdParty contained eval_buffer_size +syn keyword ngxDirectiveThirdParty contained eval_override_content_type +syn keyword ngxDirectiveThirdParty contained eval_subrequest_in_memory " OpenSSL Version Module " Nginx OpenSSL version check at startup -syn keyword ngxDirectiveThirdParty openssl_version_minimum -syn keyword ngxDirectiveThirdParty openssl_builddate_minimum +syn keyword ngxDirectiveThirdParty contained openssl_version_minimum +syn keyword ngxDirectiveThirdParty contained openssl_builddate_minimum " Owner Match Module " Control access for specific owners and groups of files -syn keyword ngxDirectiveThirdParty omallow -syn keyword ngxDirectiveThirdParty omdeny +syn keyword ngxDirectiveThirdParty contained omallow +syn keyword ngxDirectiveThirdParty contained omdeny " Accept Language Module " Parses the Accept-Language header and gives the most suitable locale from a list of supported locales. -syn keyword ngxDirectiveThirdParty pagespeed +syn keyword ngxDirectiveThirdParty contained pagespeed " PHP Memcache Standard Balancer Module " Loadbalancer that is compatible to the standard loadbalancer in the php-memcache module -syn keyword ngxDirectiveThirdParty hash_key +syn keyword ngxDirectiveThirdParty contained hash_key " PHP Session Module " Nginx module to parse php sessions -syn keyword ngxDirectiveThirdParty php_session_parse -syn keyword ngxDirectiveThirdParty php_session_strip_formatting +syn keyword ngxDirectiveThirdParty contained php_session_parse +syn keyword ngxDirectiveThirdParty contained php_session_strip_formatting " Phusion Passenger Module " Passenger is an open source web application server. -syn keyword ngxDirectiveThirdParty passenger_root -syn keyword ngxDirectiveThirdParty passenger_enabled -syn keyword ngxDirectiveThirdParty passenger_base_uri -syn keyword ngxDirectiveThirdParty passenger_document_root -syn keyword ngxDirectiveThirdParty passenger_ruby -syn keyword ngxDirectiveThirdParty passenger_python -syn keyword ngxDirectiveThirdParty passenger_nodejs -syn keyword ngxDirectiveThirdParty passenger_meteor_app_settings -syn keyword ngxDirectiveThirdParty passenger_app_env -syn keyword ngxDirectiveThirdParty passenger_app_root -syn keyword ngxDirectiveThirdParty passenger_app_group_name -syn keyword ngxDirectiveThirdParty passenger_app_type -syn keyword ngxDirectiveThirdParty passenger_startup_file -syn keyword ngxDirectiveThirdParty passenger_restart_dir -syn keyword ngxDirectiveThirdParty passenger_spawn_method -syn keyword ngxDirectiveThirdParty passenger_env_var -syn keyword ngxDirectiveThirdParty passenger_load_shell_envvars -syn keyword ngxDirectiveThirdParty passenger_rolling_restarts -syn keyword ngxDirectiveThirdParty passenger_resist_deployment_errors -syn keyword ngxDirectiveThirdParty passenger_user_switching -syn keyword ngxDirectiveThirdParty passenger_user -syn keyword ngxDirectiveThirdParty passenger_group -syn keyword ngxDirectiveThirdParty passenger_default_user -syn keyword ngxDirectiveThirdParty passenger_default_group -syn keyword ngxDirectiveThirdParty passenger_show_version_in_header -syn keyword ngxDirectiveThirdParty passenger_friendly_error_pages -syn keyword ngxDirectiveThirdParty passenger_disable_security_update_check -syn keyword ngxDirectiveThirdParty passenger_security_update_check_proxy -syn keyword ngxDirectiveThirdParty passenger_max_pool_size -syn keyword ngxDirectiveThirdParty passenger_min_instances -syn keyword ngxDirectiveThirdParty passenger_max_instances -syn keyword ngxDirectiveThirdParty passenger_max_instances_per_app -syn keyword ngxDirectiveThirdParty passenger_pool_idle_time -syn keyword ngxDirectiveThirdParty passenger_max_preloader_idle_time -syn keyword ngxDirectiveThirdParty passenger_force_max_concurrent_requests_per_process -syn keyword ngxDirectiveThirdParty passenger_start_timeout -syn keyword ngxDirectiveThirdParty passenger_concurrency_model -syn keyword ngxDirectiveThirdParty passenger_thread_count -syn keyword ngxDirectiveThirdParty passenger_max_requests -syn keyword ngxDirectiveThirdParty passenger_max_request_time -syn keyword ngxDirectiveThirdParty passenger_memory_limit -syn keyword ngxDirectiveThirdParty passenger_stat_throttle_rate -syn keyword ngxDirectiveThirdParty passenger_core_file_descriptor_ulimit -syn keyword ngxDirectiveThirdParty passenger_app_file_descriptor_ulimit -syn keyword ngxDirectiveThirdParty passenger_pre_start -syn keyword ngxDirectiveThirdParty passenger_set_header -syn keyword ngxDirectiveThirdParty passenger_max_request_queue_size -syn keyword ngxDirectiveThirdParty passenger_request_queue_overflow_status_code -syn keyword ngxDirectiveThirdParty passenger_sticky_sessions -syn keyword ngxDirectiveThirdParty passenger_sticky_sessions_cookie_name -syn keyword ngxDirectiveThirdParty passenger_abort_websockets_on_process_shutdown -syn keyword ngxDirectiveThirdParty passenger_ignore_client_abort -syn keyword ngxDirectiveThirdParty passenger_intercept_errors -syn keyword ngxDirectiveThirdParty passenger_pass_header -syn keyword ngxDirectiveThirdParty passenger_ignore_headers -syn keyword ngxDirectiveThirdParty passenger_headers_hash_bucket_size -syn keyword ngxDirectiveThirdParty passenger_headers_hash_max_size -syn keyword ngxDirectiveThirdParty passenger_buffer_response -syn keyword ngxDirectiveThirdParty passenger_response_buffer_high_watermark -syn keyword ngxDirectiveThirdParty passenger_buffer_size, passenger_buffers, passenger_busy_buffers_size -syn keyword ngxDirectiveThirdParty passenger_socket_backlog -syn keyword ngxDirectiveThirdParty passenger_log_level -syn keyword ngxDirectiveThirdParty passenger_log_file -syn keyword ngxDirectiveThirdParty passenger_file_descriptor_log_file -syn keyword ngxDirectiveThirdParty passenger_debugger -syn keyword ngxDirectiveThirdParty passenger_instance_registry_dir -syn keyword ngxDirectiveThirdParty passenger_data_buffer_dir -syn keyword ngxDirectiveThirdParty passenger_fly_with -syn keyword ngxDirectiveThirdParty union_station_support -syn keyword ngxDirectiveThirdParty union_station_key -syn keyword ngxDirectiveThirdParty union_station_proxy_address -syn keyword ngxDirectiveThirdParty union_station_filter -syn keyword ngxDirectiveThirdParty union_station_gateway_address -syn keyword ngxDirectiveThirdParty union_station_gateway_port -syn keyword ngxDirectiveThirdParty union_station_gateway_cert -syn keyword ngxDirectiveDeprecated rails_spawn_method -syn keyword ngxDirectiveDeprecated passenger_debug_log_file +syn keyword ngxDirectiveThirdParty contained passenger_root +syn keyword ngxDirectiveThirdParty contained passenger_enabled +syn keyword ngxDirectiveThirdParty contained passenger_base_uri +syn keyword ngxDirectiveThirdParty contained passenger_document_root +syn keyword ngxDirectiveThirdParty contained passenger_ruby +syn keyword ngxDirectiveThirdParty contained passenger_python +syn keyword ngxDirectiveThirdParty contained passenger_nodejs +syn keyword ngxDirectiveThirdParty contained passenger_meteor_app_settings +syn keyword ngxDirectiveThirdParty contained passenger_app_env +syn keyword ngxDirectiveThirdParty contained passenger_app_root +syn keyword ngxDirectiveThirdParty contained passenger_app_group_name +syn keyword ngxDirectiveThirdParty contained passenger_app_type +syn keyword ngxDirectiveThirdParty contained passenger_startup_file +syn keyword ngxDirectiveThirdParty contained passenger_restart_dir +syn keyword ngxDirectiveThirdParty contained passenger_spawn_method +syn keyword ngxDirectiveThirdParty contained passenger_env_var +syn keyword ngxDirectiveThirdParty contained passenger_load_shell_envvars +syn keyword ngxDirectiveThirdParty contained passenger_rolling_restarts +syn keyword ngxDirectiveThirdParty contained passenger_resist_deployment_errors +syn keyword ngxDirectiveThirdParty contained passenger_user_switching +syn keyword ngxDirectiveThirdParty contained passenger_user +syn keyword ngxDirectiveThirdParty contained passenger_group +syn keyword ngxDirectiveThirdParty contained passenger_default_user +syn keyword ngxDirectiveThirdParty contained passenger_default_group +syn keyword ngxDirectiveThirdParty contained passenger_show_version_in_header +syn keyword ngxDirectiveThirdParty contained passenger_friendly_error_pages +syn keyword ngxDirectiveThirdParty contained passenger_disable_security_update_check +syn keyword ngxDirectiveThirdParty contained passenger_security_update_check_proxy +syn keyword ngxDirectiveThirdParty contained passenger_max_pool_size +syn keyword ngxDirectiveThirdParty contained passenger_min_instances +syn keyword ngxDirectiveThirdParty contained passenger_max_instances +syn keyword ngxDirectiveThirdParty contained passenger_max_instances_per_app +syn keyword ngxDirectiveThirdParty contained passenger_pool_idle_time +syn keyword ngxDirectiveThirdParty contained passenger_max_preloader_idle_time +syn keyword ngxDirectiveThirdParty contained passenger_force_max_concurrent_requests_per_process +syn keyword ngxDirectiveThirdParty contained passenger_start_timeout +syn keyword ngxDirectiveThirdParty contained passenger_concurrency_model +syn keyword ngxDirectiveThirdParty contained passenger_thread_count +syn keyword ngxDirectiveThirdParty contained passenger_max_requests +syn keyword ngxDirectiveThirdParty contained passenger_max_request_time +syn keyword ngxDirectiveThirdParty contained passenger_memory_limit +syn keyword ngxDirectiveThirdParty contained passenger_stat_throttle_rate +syn keyword ngxDirectiveThirdParty contained passenger_core_file_descriptor_ulimit +syn keyword ngxDirectiveThirdParty contained passenger_app_file_descriptor_ulimit +syn keyword ngxDirectiveThirdParty contained passenger_pre_start +syn keyword ngxDirectiveThirdParty contained passenger_set_header +syn keyword ngxDirectiveThirdParty contained passenger_max_request_queue_size +syn keyword ngxDirectiveThirdParty contained passenger_request_queue_overflow_status_code +syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions +syn keyword ngxDirectiveThirdParty contained passenger_sticky_sessions_cookie_name +syn keyword ngxDirectiveThirdParty contained passenger_abort_websockets_on_process_shutdown +syn keyword ngxDirectiveThirdParty contained passenger_ignore_client_abort +syn keyword ngxDirectiveThirdParty contained passenger_intercept_errors +syn keyword ngxDirectiveThirdParty contained passenger_pass_header +syn keyword ngxDirectiveThirdParty contained passenger_ignore_headers +syn keyword ngxDirectiveThirdParty contained passenger_headers_hash_bucket_size +syn keyword ngxDirectiveThirdParty contained passenger_headers_hash_max_size +syn keyword ngxDirectiveThirdParty contained passenger_buffer_response +syn keyword ngxDirectiveThirdParty contained passenger_response_buffer_high_watermark +syn keyword ngxDirectiveThirdParty contained passenger_buffer_size, passenger_buffers, passenger_busy_buffers_size +syn keyword ngxDirectiveThirdParty contained passenger_socket_backlog +syn keyword ngxDirectiveThirdParty contained passenger_log_level +syn keyword ngxDirectiveThirdParty contained passenger_log_file +syn keyword ngxDirectiveThirdParty contained passenger_file_descriptor_log_file +syn keyword ngxDirectiveThirdParty contained passenger_debugger +syn keyword ngxDirectiveThirdParty contained passenger_instance_registry_dir +syn keyword ngxDirectiveThirdParty contained passenger_data_buffer_dir +syn keyword ngxDirectiveThirdParty contained passenger_fly_with +syn keyword ngxDirectiveThirdParty contained union_station_support +syn keyword ngxDirectiveThirdParty contained union_station_key +syn keyword ngxDirectiveThirdParty contained union_station_proxy_address +syn keyword ngxDirectiveThirdParty contained union_station_filter +syn keyword ngxDirectiveThirdParty contained union_station_gateway_address +syn keyword ngxDirectiveThirdParty contained union_station_gateway_port +syn keyword ngxDirectiveThirdParty contained union_station_gateway_cert +syn keyword ngxDirectiveDeprecated contained rails_spawn_method +syn keyword ngxDirectiveDeprecated contained passenger_debug_log_file " Postgres Module " Upstream module that allows nginx to communicate directly with PostgreSQL database. -syn keyword ngxDirectiveThirdParty postgres_server -syn keyword ngxDirectiveThirdParty postgres_keepalive -syn keyword ngxDirectiveThirdParty postgres_pass -syn keyword ngxDirectiveThirdParty postgres_query -syn keyword ngxDirectiveThirdParty postgres_rewrite -syn keyword ngxDirectiveThirdParty postgres_output -syn keyword ngxDirectiveThirdParty postgres_set -syn keyword ngxDirectiveThirdParty postgres_escape -syn keyword ngxDirectiveThirdParty postgres_connect_timeout -syn keyword ngxDirectiveThirdParty postgres_result_timeout +syn keyword ngxDirectiveThirdParty contained postgres_server +syn keyword ngxDirectiveThirdParty contained postgres_keepalive +syn keyword ngxDirectiveThirdParty contained postgres_pass +syn keyword ngxDirectiveThirdParty contained postgres_query +syn keyword ngxDirectiveThirdParty contained postgres_rewrite +syn keyword ngxDirectiveThirdParty contained postgres_output +syn keyword ngxDirectiveThirdParty contained postgres_set +syn keyword ngxDirectiveThirdParty contained postgres_escape +syn keyword ngxDirectiveThirdParty contained postgres_connect_timeout +syn keyword ngxDirectiveThirdParty contained postgres_result_timeout " Pubcookie Module " Authorizes users using encrypted cookies -syn keyword ngxDirectiveThirdParty pubcookie_inactive_expire -syn keyword ngxDirectiveThirdParty pubcookie_hard_expire -syn keyword ngxDirectiveThirdParty pubcookie_app_id -syn keyword ngxDirectiveThirdParty pubcookie_dir_depth -syn keyword ngxDirectiveThirdParty pubcookie_catenate_app_ids -syn keyword ngxDirectiveThirdParty pubcookie_app_srv_id -syn keyword ngxDirectiveThirdParty pubcookie_login -syn keyword ngxDirectiveThirdParty pubcookie_login_method -syn keyword ngxDirectiveThirdParty pubcookie_post -syn keyword ngxDirectiveThirdParty pubcookie_domain -syn keyword ngxDirectiveThirdParty pubcookie_granting_cert_file -syn keyword ngxDirectiveThirdParty pubcookie_session_key_file -syn keyword ngxDirectiveThirdParty pubcookie_session_cert_file -syn keyword ngxDirectiveThirdParty pubcookie_crypt_key_file -syn keyword ngxDirectiveThirdParty pubcookie_end_session -syn keyword ngxDirectiveThirdParty pubcookie_encryption -syn keyword ngxDirectiveThirdParty pubcookie_session_reauth -syn keyword ngxDirectiveThirdParty pubcookie_auth_type_names -syn keyword ngxDirectiveThirdParty pubcookie_no_prompt -syn keyword ngxDirectiveThirdParty pubcookie_on_demand -syn keyword ngxDirectiveThirdParty pubcookie_addl_request -syn keyword ngxDirectiveThirdParty pubcookie_no_obscure_cookies -syn keyword ngxDirectiveThirdParty pubcookie_no_clean_creds -syn keyword ngxDirectiveThirdParty pubcookie_egd_device -syn keyword ngxDirectiveThirdParty pubcookie_no_blank -syn keyword ngxDirectiveThirdParty pubcookie_super_debug -syn keyword ngxDirectiveThirdParty pubcookie_set_remote_user +syn keyword ngxDirectiveThirdParty contained pubcookie_inactive_expire +syn keyword ngxDirectiveThirdParty contained pubcookie_hard_expire +syn keyword ngxDirectiveThirdParty contained pubcookie_app_id +syn keyword ngxDirectiveThirdParty contained pubcookie_dir_depth +syn keyword ngxDirectiveThirdParty contained pubcookie_catenate_app_ids +syn keyword ngxDirectiveThirdParty contained pubcookie_app_srv_id +syn keyword ngxDirectiveThirdParty contained pubcookie_login +syn keyword ngxDirectiveThirdParty contained pubcookie_login_method +syn keyword ngxDirectiveThirdParty contained pubcookie_post +syn keyword ngxDirectiveThirdParty contained pubcookie_domain +syn keyword ngxDirectiveThirdParty contained pubcookie_granting_cert_file +syn keyword ngxDirectiveThirdParty contained pubcookie_session_key_file +syn keyword ngxDirectiveThirdParty contained pubcookie_session_cert_file +syn keyword ngxDirectiveThirdParty contained pubcookie_crypt_key_file +syn keyword ngxDirectiveThirdParty contained pubcookie_end_session +syn keyword ngxDirectiveThirdParty contained pubcookie_encryption +syn keyword ngxDirectiveThirdParty contained pubcookie_session_reauth +syn keyword ngxDirectiveThirdParty contained pubcookie_auth_type_names +syn keyword ngxDirectiveThirdParty contained pubcookie_no_prompt +syn keyword ngxDirectiveThirdParty contained pubcookie_on_demand +syn keyword ngxDirectiveThirdParty contained pubcookie_addl_request +syn keyword ngxDirectiveThirdParty contained pubcookie_no_obscure_cookies +syn keyword ngxDirectiveThirdParty contained pubcookie_no_clean_creds +syn keyword ngxDirectiveThirdParty contained pubcookie_egd_device +syn keyword ngxDirectiveThirdParty contained pubcookie_no_blank +syn keyword ngxDirectiveThirdParty contained pubcookie_super_debug +syn keyword ngxDirectiveThirdParty contained pubcookie_set_remote_user " Push Stream Module " A pure stream http push technology for your Nginx setup -syn keyword ngxDirectiveThirdParty push_stream_channels_statistics -syn keyword ngxDirectiveThirdParty push_stream_publisher -syn keyword ngxDirectiveThirdParty push_stream_subscriber -syn keyword ngxDirectiveThirdParty push_stream_shared_memory_size -syn keyword ngxDirectiveThirdParty push_stream_channel_deleted_message_text -syn keyword ngxDirectiveThirdParty push_stream_channel_inactivity_time -syn keyword ngxDirectiveThirdParty push_stream_ping_message_text -syn keyword ngxDirectiveThirdParty push_stream_timeout_with_body -syn keyword ngxDirectiveThirdParty push_stream_message_ttl -syn keyword ngxDirectiveThirdParty push_stream_max_subscribers_per_channel -syn keyword ngxDirectiveThirdParty push_stream_max_messages_stored_per_channel -syn keyword ngxDirectiveThirdParty push_stream_max_channel_id_length -syn keyword ngxDirectiveThirdParty push_stream_max_number_of_channels -syn keyword ngxDirectiveThirdParty push_stream_max_number_of_wildcard_channels -syn keyword ngxDirectiveThirdParty push_stream_wildcard_channel_prefix -syn keyword ngxDirectiveThirdParty push_stream_events_channel_id -syn keyword ngxDirectiveThirdParty push_stream_channels_path -syn keyword ngxDirectiveThirdParty push_stream_store_messages -syn keyword ngxDirectiveThirdParty push_stream_channel_info_on_publish -syn keyword ngxDirectiveThirdParty push_stream_authorized_channels_only -syn keyword ngxDirectiveThirdParty push_stream_header_template_file -syn keyword ngxDirectiveThirdParty push_stream_header_template -syn keyword ngxDirectiveThirdParty push_stream_message_template -syn keyword ngxDirectiveThirdParty push_stream_footer_template -syn keyword ngxDirectiveThirdParty push_stream_wildcard_channel_max_qtd -syn keyword ngxDirectiveThirdParty push_stream_ping_message_interval -syn keyword ngxDirectiveThirdParty push_stream_subscriber_connection_ttl -syn keyword ngxDirectiveThirdParty push_stream_longpolling_connection_ttl -syn keyword ngxDirectiveThirdParty push_stream_websocket_allow_publish -syn keyword ngxDirectiveThirdParty push_stream_last_received_message_time -syn keyword ngxDirectiveThirdParty push_stream_last_received_message_tag -syn keyword ngxDirectiveThirdParty push_stream_last_event_id -syn keyword ngxDirectiveThirdParty push_stream_user_agent -syn keyword ngxDirectiveThirdParty push_stream_padding_by_user_agent -syn keyword ngxDirectiveThirdParty push_stream_allowed_origins -syn keyword ngxDirectiveThirdParty push_stream_allow_connections_to_events_channel +syn keyword ngxDirectiveThirdParty contained push_stream_channels_statistics +syn keyword ngxDirectiveThirdParty contained push_stream_publisher +syn keyword ngxDirectiveThirdParty contained push_stream_subscriber +syn keyword ngxDirectiveThirdParty contained push_stream_shared_memory_size +syn keyword ngxDirectiveThirdParty contained push_stream_channel_deleted_message_text +syn keyword ngxDirectiveThirdParty contained push_stream_channel_inactivity_time +syn keyword ngxDirectiveThirdParty contained push_stream_ping_message_text +syn keyword ngxDirectiveThirdParty contained push_stream_timeout_with_body +syn keyword ngxDirectiveThirdParty contained push_stream_message_ttl +syn keyword ngxDirectiveThirdParty contained push_stream_max_subscribers_per_channel +syn keyword ngxDirectiveThirdParty contained push_stream_max_messages_stored_per_channel +syn keyword ngxDirectiveThirdParty contained push_stream_max_channel_id_length +syn keyword ngxDirectiveThirdParty contained push_stream_max_number_of_channels +syn keyword ngxDirectiveThirdParty contained push_stream_max_number_of_wildcard_channels +syn keyword ngxDirectiveThirdParty contained push_stream_wildcard_channel_prefix +syn keyword ngxDirectiveThirdParty contained push_stream_events_channel_id +syn keyword ngxDirectiveThirdParty contained push_stream_channels_path +syn keyword ngxDirectiveThirdParty contained push_stream_store_messages +syn keyword ngxDirectiveThirdParty contained push_stream_channel_info_on_publish +syn keyword ngxDirectiveThirdParty contained push_stream_authorized_channels_only +syn keyword ngxDirectiveThirdParty contained push_stream_header_template_file +syn keyword ngxDirectiveThirdParty contained push_stream_header_template +syn keyword ngxDirectiveThirdParty contained push_stream_message_template +syn keyword ngxDirectiveThirdParty contained push_stream_footer_template +syn keyword ngxDirectiveThirdParty contained push_stream_wildcard_channel_max_qtd +syn keyword ngxDirectiveThirdParty contained push_stream_ping_message_interval +syn keyword ngxDirectiveThirdParty contained push_stream_subscriber_connection_ttl +syn keyword ngxDirectiveThirdParty contained push_stream_longpolling_connection_ttl +syn keyword ngxDirectiveThirdParty contained push_stream_websocket_allow_publish +syn keyword ngxDirectiveThirdParty contained push_stream_last_received_message_time +syn keyword ngxDirectiveThirdParty contained push_stream_last_received_message_tag +syn keyword ngxDirectiveThirdParty contained push_stream_last_event_id +syn keyword ngxDirectiveThirdParty contained push_stream_user_agent +syn keyword ngxDirectiveThirdParty contained push_stream_padding_by_user_agent +syn keyword ngxDirectiveThirdParty contained push_stream_allowed_origins +syn keyword ngxDirectiveThirdParty contained push_stream_allow_connections_to_events_channel " rDNS Module " Make a reverse DNS (rDNS) lookup for incoming connection and provides simple access control of incoming hostname by allow/deny rules -syn keyword ngxDirectiveThirdParty rdns -syn keyword ngxDirectiveThirdParty rdns_allow -syn keyword ngxDirectiveThirdParty rdns_deny +syn keyword ngxDirectiveThirdParty contained rdns +syn keyword ngxDirectiveThirdParty contained rdns_allow +syn keyword ngxDirectiveThirdParty contained rdns_deny " RDS CSV Module " Nginx output filter module to convert Resty-DBD-Streams (RDS) to Comma-Separated Values (CSV) -syn keyword ngxDirectiveThirdParty rds_csv -syn keyword ngxDirectiveThirdParty rds_csv_row_terminator -syn keyword ngxDirectiveThirdParty rds_csv_field_separator -syn keyword ngxDirectiveThirdParty rds_csv_field_name_header -syn keyword ngxDirectiveThirdParty rds_csv_content_type -syn keyword ngxDirectiveThirdParty rds_csv_buffer_size +syn keyword ngxDirectiveThirdParty contained rds_csv +syn keyword ngxDirectiveThirdParty contained rds_csv_row_terminator +syn keyword ngxDirectiveThirdParty contained rds_csv_field_separator +syn keyword ngxDirectiveThirdParty contained rds_csv_field_name_header +syn keyword ngxDirectiveThirdParty contained rds_csv_content_type +syn keyword ngxDirectiveThirdParty contained rds_csv_buffer_size " RDS JSON Module " An output filter that formats Resty DBD Streams generated by ngx_drizzle and others to JSON -syn keyword ngxDirectiveThirdParty rds_json -syn keyword ngxDirectiveThirdParty rds_json_buffer_size -syn keyword ngxDirectiveThirdParty rds_json_format -syn keyword ngxDirectiveThirdParty rds_json_root -syn keyword ngxDirectiveThirdParty rds_json_success_property -syn keyword ngxDirectiveThirdParty rds_json_user_property -syn keyword ngxDirectiveThirdParty rds_json_errcode_key -syn keyword ngxDirectiveThirdParty rds_json_errstr_key -syn keyword ngxDirectiveThirdParty rds_json_ret -syn keyword ngxDirectiveThirdParty rds_json_content_type +syn keyword ngxDirectiveThirdParty contained rds_json +syn keyword ngxDirectiveThirdParty contained rds_json_buffer_size +syn keyword ngxDirectiveThirdParty contained rds_json_format +syn keyword ngxDirectiveThirdParty contained rds_json_root +syn keyword ngxDirectiveThirdParty contained rds_json_success_property +syn keyword ngxDirectiveThirdParty contained rds_json_user_property +syn keyword ngxDirectiveThirdParty contained rds_json_errcode_key +syn keyword ngxDirectiveThirdParty contained rds_json_errstr_key +syn keyword ngxDirectiveThirdParty contained rds_json_ret +syn keyword ngxDirectiveThirdParty contained rds_json_content_type " Redis Module " Use this module to perform simple caching -syn keyword ngxDirectiveThirdParty redis_pass -syn keyword ngxDirectiveThirdParty redis_bind -syn keyword ngxDirectiveThirdParty redis_connect_timeout -syn keyword ngxDirectiveThirdParty redis_read_timeout -syn keyword ngxDirectiveThirdParty redis_send_timeout -syn keyword ngxDirectiveThirdParty redis_buffer_size -syn keyword ngxDirectiveThirdParty redis_next_upstream -syn keyword ngxDirectiveThirdParty redis_gzip_flag +syn keyword ngxDirectiveThirdParty contained redis_pass +syn keyword ngxDirectiveThirdParty contained redis_bind +syn keyword ngxDirectiveThirdParty contained redis_connect_timeout +syn keyword ngxDirectiveThirdParty contained redis_read_timeout +syn keyword ngxDirectiveThirdParty contained redis_send_timeout +syn keyword ngxDirectiveThirdParty contained redis_buffer_size +syn keyword ngxDirectiveThirdParty contained redis_next_upstream +syn keyword ngxDirectiveThirdParty contained redis_gzip_flag " Redis 2 Module " Nginx upstream module for the Redis 2.0 protocol -syn keyword ngxDirectiveThirdParty redis2_query -syn keyword ngxDirectiveThirdParty redis2_raw_query -syn keyword ngxDirectiveThirdParty redis2_raw_queries -syn keyword ngxDirectiveThirdParty redis2_literal_raw_query -syn keyword ngxDirectiveThirdParty redis2_pass -syn keyword ngxDirectiveThirdParty redis2_connect_timeout -syn keyword ngxDirectiveThirdParty redis2_send_timeout -syn keyword ngxDirectiveThirdParty redis2_read_timeout -syn keyword ngxDirectiveThirdParty redis2_buffer_size -syn keyword ngxDirectiveThirdParty redis2_next_upstream +syn keyword ngxDirectiveThirdParty contained redis2_query +syn keyword ngxDirectiveThirdParty contained redis2_raw_query +syn keyword ngxDirectiveThirdParty contained redis2_raw_queries +syn keyword ngxDirectiveThirdParty contained redis2_literal_raw_query +syn keyword ngxDirectiveThirdParty contained redis2_pass +syn keyword ngxDirectiveThirdParty contained redis2_connect_timeout +syn keyword ngxDirectiveThirdParty contained redis2_send_timeout +syn keyword ngxDirectiveThirdParty contained redis2_read_timeout +syn keyword ngxDirectiveThirdParty contained redis2_buffer_size +syn keyword ngxDirectiveThirdParty contained redis2_next_upstream " Replace Filter Module " Streaming regular expression replacement in response bodies -syn keyword ngxDirectiveThirdParty replace_filter -syn keyword ngxDirectiveThirdParty replace_filter_types -syn keyword ngxDirectiveThirdParty replace_filter_max_buffered_size -syn keyword ngxDirectiveThirdParty replace_filter_last_modified -syn keyword ngxDirectiveThirdParty replace_filter_skip +syn keyword ngxDirectiveThirdParty contained replace_filter +syn keyword ngxDirectiveThirdParty contained replace_filter_types +syn keyword ngxDirectiveThirdParty contained replace_filter_max_buffered_size +syn keyword ngxDirectiveThirdParty contained replace_filter_last_modified +syn keyword ngxDirectiveThirdParty contained replace_filter_skip " Roboo Module " HTTP Robot Mitigator " RRD Graph Module " This module provides an HTTP interface to RRDtool's graphing facilities. -syn keyword ngxDirectiveThirdParty rrd_graph -syn keyword ngxDirectiveThirdParty rrd_graph_root +syn keyword ngxDirectiveThirdParty contained rrd_graph +syn keyword ngxDirectiveThirdParty contained rrd_graph_root " RTMP Module " NGINX-based Media Streaming Server -syn keyword ngxDirectiveThirdParty rtmp -" syn keyword ngxDirectiveThirdParty server -" syn keyword ngxDirectiveThirdParty listen -syn keyword ngxDirectiveThirdParty application -" syn keyword ngxDirectiveThirdParty timeout -syn keyword ngxDirectiveThirdParty ping -syn keyword ngxDirectiveThirdParty ping_timeout -syn keyword ngxDirectiveThirdParty max_streams -syn keyword ngxDirectiveThirdParty ack_window -syn keyword ngxDirectiveThirdParty chunk_size -syn keyword ngxDirectiveThirdParty max_queue -syn keyword ngxDirectiveThirdParty max_message -syn keyword ngxDirectiveThirdParty out_queue -syn keyword ngxDirectiveThirdParty out_cork -" syn keyword ngxDirectiveThirdParty allow -" syn keyword ngxDirectiveThirdParty deny -syn keyword ngxDirectiveThirdParty exec_push -syn keyword ngxDirectiveThirdParty exec_pull -syn keyword ngxDirectiveThirdParty exec -syn keyword ngxDirectiveThirdParty exec_options -syn keyword ngxDirectiveThirdParty exec_static -syn keyword ngxDirectiveThirdParty exec_kill_signal -syn keyword ngxDirectiveThirdParty respawn -syn keyword ngxDirectiveThirdParty respawn_timeout -syn keyword ngxDirectiveThirdParty exec_publish -syn keyword ngxDirectiveThirdParty exec_play -syn keyword ngxDirectiveThirdParty exec_play_done -syn keyword ngxDirectiveThirdParty exec_publish_done -syn keyword ngxDirectiveThirdParty exec_record_done -syn keyword ngxDirectiveThirdParty live -syn keyword ngxDirectiveThirdParty meta -syn keyword ngxDirectiveThirdParty interleave -syn keyword ngxDirectiveThirdParty wait_key -syn keyword ngxDirectiveThirdParty wait_video -syn keyword ngxDirectiveThirdParty publish_notify -syn keyword ngxDirectiveThirdParty drop_idle_publisher -syn keyword ngxDirectiveThirdParty sync -syn keyword ngxDirectiveThirdParty play_restart -syn keyword ngxDirectiveThirdParty idle_streams -syn keyword ngxDirectiveThirdParty record -syn keyword ngxDirectiveThirdParty record_path -syn keyword ngxDirectiveThirdParty record_suffix -syn keyword ngxDirectiveThirdParty record_unique -syn keyword ngxDirectiveThirdParty record_append -syn keyword ngxDirectiveThirdParty record_lock -syn keyword ngxDirectiveThirdParty record_max_size -syn keyword ngxDirectiveThirdParty record_max_frames -syn keyword ngxDirectiveThirdParty record_interval -syn keyword ngxDirectiveThirdParty recorder -syn keyword ngxDirectiveThirdParty record_notify -syn keyword ngxDirectiveThirdParty play -syn keyword ngxDirectiveThirdParty play_temp_path -syn keyword ngxDirectiveThirdParty play_local_path -syn keyword ngxDirectiveThirdParty pull -syn keyword ngxDirectiveThirdParty push -syn keyword ngxDirectiveThirdParty push_reconnect -syn keyword ngxDirectiveThirdParty session_relay -syn keyword ngxDirectiveThirdParty on_connect -syn keyword ngxDirectiveThirdParty on_play -syn keyword ngxDirectiveThirdParty on_publish -syn keyword ngxDirectiveThirdParty on_done -syn keyword ngxDirectiveThirdParty on_play_done -syn keyword ngxDirectiveThirdParty on_publish_done -syn keyword ngxDirectiveThirdParty on_record_done -syn keyword ngxDirectiveThirdParty on_update -syn keyword ngxDirectiveThirdParty notify_update_timeout -syn keyword ngxDirectiveThirdParty notify_update_strict -syn keyword ngxDirectiveThirdParty notify_relay_redirect -syn keyword ngxDirectiveThirdParty notify_method -syn keyword ngxDirectiveThirdParty hls -syn keyword ngxDirectiveThirdParty hls_path -syn keyword ngxDirectiveThirdParty hls_fragment -syn keyword ngxDirectiveThirdParty hls_playlist_length -syn keyword ngxDirectiveThirdParty hls_sync -syn keyword ngxDirectiveThirdParty hls_continuous -syn keyword ngxDirectiveThirdParty hls_nested -syn keyword ngxDirectiveThirdParty hls_base_url -syn keyword ngxDirectiveThirdParty hls_cleanup -syn keyword ngxDirectiveThirdParty hls_fragment_naming -syn keyword ngxDirectiveThirdParty hls_fragment_slicing -syn keyword ngxDirectiveThirdParty hls_variant -syn keyword ngxDirectiveThirdParty hls_type -syn keyword ngxDirectiveThirdParty hls_keys -syn keyword ngxDirectiveThirdParty hls_key_path -syn keyword ngxDirectiveThirdParty hls_key_url -syn keyword ngxDirectiveThirdParty hls_fragments_per_key -syn keyword ngxDirectiveThirdParty dash -syn keyword ngxDirectiveThirdParty dash_path -syn keyword ngxDirectiveThirdParty dash_fragment -syn keyword ngxDirectiveThirdParty dash_playlist_length -syn keyword ngxDirectiveThirdParty dash_nested -syn keyword ngxDirectiveThirdParty dash_cleanup -" syn keyword ngxDirectiveThirdParty access_log -" syn keyword ngxDirectiveThirdParty log_format -syn keyword ngxDirectiveThirdParty max_connections -syn keyword ngxDirectiveThirdParty rtmp_stat -syn keyword ngxDirectiveThirdParty rtmp_stat_stylesheet -syn keyword ngxDirectiveThirdParty rtmp_auto_push -syn keyword ngxDirectiveThirdParty rtmp_auto_push_reconnect -syn keyword ngxDirectiveThirdParty rtmp_socket_dir -syn keyword ngxDirectiveThirdParty rtmp_control +syn keyword ngxDirectiveThirdParty contained rtmp +" syn keyword ngxDirectiveThirdParty contained server +" syn keyword ngxDirectiveThirdParty contained listen +syn keyword ngxDirectiveThirdParty contained application +" syn keyword ngxDirectiveThirdParty contained timeout +syn keyword ngxDirectiveThirdParty contained ping +syn keyword ngxDirectiveThirdParty contained ping_timeout +syn keyword ngxDirectiveThirdParty contained max_streams +syn keyword ngxDirectiveThirdParty contained ack_window +syn keyword ngxDirectiveThirdParty contained chunk_size +syn keyword ngxDirectiveThirdParty contained max_queue +syn keyword ngxDirectiveThirdParty contained max_message +syn keyword ngxDirectiveThirdParty contained out_queue +syn keyword ngxDirectiveThirdParty contained out_cork +" syn keyword ngxDirectiveThirdParty contained allow +" syn keyword ngxDirectiveThirdParty contained deny +syn keyword ngxDirectiveThirdParty contained exec_push +syn keyword ngxDirectiveThirdParty contained exec_pull +syn keyword ngxDirectiveThirdParty contained exec +syn keyword ngxDirectiveThirdParty contained exec_options +syn keyword ngxDirectiveThirdParty contained exec_static +syn keyword ngxDirectiveThirdParty contained exec_kill_signal +syn keyword ngxDirectiveThirdParty contained respawn +syn keyword ngxDirectiveThirdParty contained respawn_timeout +syn keyword ngxDirectiveThirdParty contained exec_publish +syn keyword ngxDirectiveThirdParty contained exec_play +syn keyword ngxDirectiveThirdParty contained exec_play_done +syn keyword ngxDirectiveThirdParty contained exec_publish_done +syn keyword ngxDirectiveThirdParty contained exec_record_done +syn keyword ngxDirectiveThirdParty contained live +syn keyword ngxDirectiveThirdParty contained meta +syn keyword ngxDirectiveThirdParty contained interleave +syn keyword ngxDirectiveThirdParty contained wait_key +syn keyword ngxDirectiveThirdParty contained wait_video +syn keyword ngxDirectiveThirdParty contained publish_notify +syn keyword ngxDirectiveThirdParty contained drop_idle_publisher +syn keyword ngxDirectiveThirdParty contained sync +syn keyword ngxDirectiveThirdParty contained play_restart +syn keyword ngxDirectiveThirdParty contained idle_streams +syn keyword ngxDirectiveThirdParty contained record +syn keyword ngxDirectiveThirdParty contained record_path +syn keyword ngxDirectiveThirdParty contained record_suffix +syn keyword ngxDirectiveThirdParty contained record_unique +syn keyword ngxDirectiveThirdParty contained record_append +syn keyword ngxDirectiveThirdParty contained record_lock +syn keyword ngxDirectiveThirdParty contained record_max_size +syn keyword ngxDirectiveThirdParty contained record_max_frames +syn keyword ngxDirectiveThirdParty contained record_interval +syn keyword ngxDirectiveThirdParty contained recorder +syn keyword ngxDirectiveThirdParty contained record_notify +syn keyword ngxDirectiveThirdParty contained play +syn keyword ngxDirectiveThirdParty contained play_temp_path +syn keyword ngxDirectiveThirdParty contained play_local_path +syn keyword ngxDirectiveThirdParty contained pull +syn keyword ngxDirectiveThirdParty contained push +syn keyword ngxDirectiveThirdParty contained push_reconnect +syn keyword ngxDirectiveThirdParty contained session_relay +syn keyword ngxDirectiveThirdParty contained on_connect +syn keyword ngxDirectiveThirdParty contained on_play +syn keyword ngxDirectiveThirdParty contained on_publish +syn keyword ngxDirectiveThirdParty contained on_done +syn keyword ngxDirectiveThirdParty contained on_play_done +syn keyword ngxDirectiveThirdParty contained on_publish_done +syn keyword ngxDirectiveThirdParty contained on_record_done +syn keyword ngxDirectiveThirdParty contained on_update +syn keyword ngxDirectiveThirdParty contained notify_update_timeout +syn keyword ngxDirectiveThirdParty contained notify_update_strict +syn keyword ngxDirectiveThirdParty contained notify_relay_redirect +syn keyword ngxDirectiveThirdParty contained notify_method +syn keyword ngxDirectiveThirdParty contained hls +syn keyword ngxDirectiveThirdParty contained hls_path +syn keyword ngxDirectiveThirdParty contained hls_fragment +syn keyword ngxDirectiveThirdParty contained hls_playlist_length +syn keyword ngxDirectiveThirdParty contained hls_sync +syn keyword ngxDirectiveThirdParty contained hls_continuous +syn keyword ngxDirectiveThirdParty contained hls_nested +syn keyword ngxDirectiveThirdParty contained hls_base_url +syn keyword ngxDirectiveThirdParty contained hls_cleanup +syn keyword ngxDirectiveThirdParty contained hls_fragment_naming +syn keyword ngxDirectiveThirdParty contained hls_fragment_slicing +syn keyword ngxDirectiveThirdParty contained hls_variant +syn keyword ngxDirectiveThirdParty contained hls_type +syn keyword ngxDirectiveThirdParty contained hls_keys +syn keyword ngxDirectiveThirdParty contained hls_key_path +syn keyword ngxDirectiveThirdParty contained hls_key_url +syn keyword ngxDirectiveThirdParty contained hls_fragments_per_key +syn keyword ngxDirectiveThirdParty contained dash +syn keyword ngxDirectiveThirdParty contained dash_path +syn keyword ngxDirectiveThirdParty contained dash_fragment +syn keyword ngxDirectiveThirdParty contained dash_playlist_length +syn keyword ngxDirectiveThirdParty contained dash_nested +syn keyword ngxDirectiveThirdParty contained dash_cleanup +" syn keyword ngxDirectiveThirdParty contained access_log +" syn keyword ngxDirectiveThirdParty contained log_format +syn keyword ngxDirectiveThirdParty contained max_connections +syn keyword ngxDirectiveThirdParty contained rtmp_stat +syn keyword ngxDirectiveThirdParty contained rtmp_stat_stylesheet +syn keyword ngxDirectiveThirdParty contained rtmp_auto_push +syn keyword ngxDirectiveThirdParty contained rtmp_auto_push_reconnect +syn keyword ngxDirectiveThirdParty contained rtmp_socket_dir +syn keyword ngxDirectiveThirdParty contained rtmp_control " RTMPT Module " Module for nginx to proxy rtmp using http protocol -syn keyword ngxDirectiveThirdParty rtmpt_proxy_target -syn keyword ngxDirectiveThirdParty rtmpt_proxy_rtmp_timeout -syn keyword ngxDirectiveThirdParty rtmpt_proxy_http_timeout -syn keyword ngxDirectiveThirdParty rtmpt_proxy -syn keyword ngxDirectiveThirdParty rtmpt_proxy_stat -syn keyword ngxDirectiveThirdParty rtmpt_proxy_stylesheet +syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_target +syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_rtmp_timeout +syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_http_timeout +syn keyword ngxDirectiveThirdParty contained rtmpt_proxy +syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_stat +syn keyword ngxDirectiveThirdParty contained rtmpt_proxy_stylesheet " Syntactically Awesome Module " Providing on-the-fly compiling of Sass files as an NGINX module. -syn keyword ngxDirectiveThirdParty sass_compile -syn keyword ngxDirectiveThirdParty sass_error_log -syn keyword ngxDirectiveThirdParty sass_include_path -syn keyword ngxDirectiveThirdParty sass_indent -syn keyword ngxDirectiveThirdParty sass_is_indented_syntax -syn keyword ngxDirectiveThirdParty sass_linefeed -syn keyword ngxDirectiveThirdParty sass_precision -syn keyword ngxDirectiveThirdParty sass_output_style -syn keyword ngxDirectiveThirdParty sass_source_comments -syn keyword ngxDirectiveThirdParty sass_source_map_embed +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_precision +syn keyword ngxDirectiveThirdParty contained sass_output_style +syn keyword ngxDirectiveThirdParty contained sass_source_comments +syn keyword ngxDirectiveThirdParty contained sass_source_map_embed " Secure Download Module " Enables you to create links which are only valid until a certain datetime is reached -syn keyword ngxDirectiveThirdParty secure_download -syn keyword ngxDirectiveThirdParty secure_download_secret -syn keyword ngxDirectiveThirdParty secure_download_path_mode +syn keyword ngxDirectiveThirdParty contained secure_download +syn keyword ngxDirectiveThirdParty contained secure_download_secret +syn keyword ngxDirectiveThirdParty contained secure_download_path_mode " Selective Cache Purge Module " A module to purge cache by GLOB patterns. The supported patterns are the same as supported by Redis. -syn keyword ngxDirectiveThirdParty selective_cache_purge_redis_unix_socket -syn keyword ngxDirectiveThirdParty selective_cache_purge_redis_host -syn keyword ngxDirectiveThirdParty selective_cache_purge_redis_port -syn keyword ngxDirectiveThirdParty selective_cache_purge_redis_database -syn keyword ngxDirectiveThirdParty selective_cache_purge_query +syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_unix_socket +syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_host +syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_port +syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_database +syn keyword ngxDirectiveThirdParty contained selective_cache_purge_query " Set cconv Module " Cconv rewrite set commands -syn keyword ngxDirectiveThirdParty set_cconv_to_simp -syn keyword ngxDirectiveThirdParty set_cconv_to_trad -syn keyword ngxDirectiveThirdParty set_pinyin_to_normal +syn keyword ngxDirectiveThirdParty contained set_cconv_to_simp +syn keyword ngxDirectiveThirdParty contained set_cconv_to_trad +syn keyword ngxDirectiveThirdParty contained set_pinyin_to_normal " Set Hash Module " Nginx module that allows the setting of variables to the value of a variety of hashes -syn keyword ngxDirectiveThirdParty set_md5 -syn keyword ngxDirectiveThirdParty set_md5_upper -syn keyword ngxDirectiveThirdParty set_murmur2 -syn keyword ngxDirectiveThirdParty set_murmur2_upper -syn keyword ngxDirectiveThirdParty set_sha1 -syn keyword ngxDirectiveThirdParty set_sha1_upper +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 " Set Lang Module " Provides a variety of ways for setting a variable denoting the langauge that content should be returned in. -syn keyword ngxDirectiveThirdParty set_lang -syn keyword ngxDirectiveThirdParty set_lang_method -syn keyword ngxDirectiveThirdParty lang_cookie -syn keyword ngxDirectiveThirdParty lang_get_var -syn keyword ngxDirectiveThirdParty lang_list -syn keyword ngxDirectiveThirdParty lang_post_var -syn keyword ngxDirectiveThirdParty lang_host -syn keyword ngxDirectiveThirdParty lang_referer +syn keyword ngxDirectiveThirdParty contained set_lang +syn keyword ngxDirectiveThirdParty contained set_lang_method +syn keyword ngxDirectiveThirdParty contained lang_cookie +syn keyword ngxDirectiveThirdParty contained lang_get_var +syn keyword ngxDirectiveThirdParty contained lang_list +syn keyword ngxDirectiveThirdParty contained lang_post_var +syn keyword ngxDirectiveThirdParty contained lang_host +syn keyword ngxDirectiveThirdParty contained lang_referer " Set Misc Module " Various set_xxx directives added to nginx's rewrite module -syn keyword ngxDirectiveThirdParty set_if_empty -syn keyword ngxDirectiveThirdParty set_quote_sql_str -syn keyword ngxDirectiveThirdParty set_quote_pgsql_str -syn keyword ngxDirectiveThirdParty set_quote_json_str -syn keyword ngxDirectiveThirdParty set_unescape_uri -syn keyword ngxDirectiveThirdParty set_escape_uri -syn keyword ngxDirectiveThirdParty set_hashed_upstream -syn keyword ngxDirectiveThirdParty set_encode_base32 -syn keyword ngxDirectiveThirdParty set_base32_padding -syn keyword ngxDirectiveThirdParty set_misc_base32_padding -syn keyword ngxDirectiveThirdParty set_base32_alphabet -syn keyword ngxDirectiveThirdParty set_decode_base32 -syn keyword ngxDirectiveThirdParty set_encode_base64 -syn keyword ngxDirectiveThirdParty set_decode_base64 -syn keyword ngxDirectiveThirdParty set_encode_hex -syn keyword ngxDirectiveThirdParty set_decode_hex -syn keyword ngxDirectiveThirdParty set_sha1 -syn keyword ngxDirectiveThirdParty set_md5 -syn keyword ngxDirectiveThirdParty set_hmac_sha1 -syn keyword ngxDirectiveThirdParty set_random -syn keyword ngxDirectiveThirdParty set_secure_random_alphanum -syn keyword ngxDirectiveThirdParty set_secure_random_lcalpha -syn keyword ngxDirectiveThirdParty set_rotate -syn keyword ngxDirectiveThirdParty set_local_today -syn keyword ngxDirectiveThirdParty set_formatted_gmt_time -syn keyword ngxDirectiveThirdParty set_formatted_local_time +syn keyword ngxDirectiveThirdParty contained set_if_empty +syn keyword ngxDirectiveThirdParty contained set_quote_sql_str +syn keyword ngxDirectiveThirdParty contained set_quote_pgsql_str +syn keyword ngxDirectiveThirdParty contained set_quote_json_str +syn keyword ngxDirectiveThirdParty contained set_unescape_uri +syn keyword ngxDirectiveThirdParty contained set_escape_uri +syn keyword ngxDirectiveThirdParty contained set_hashed_upstream +syn keyword ngxDirectiveThirdParty contained set_encode_base32 +syn keyword ngxDirectiveThirdParty contained set_base32_padding +syn keyword ngxDirectiveThirdParty contained set_misc_base32_padding +syn keyword ngxDirectiveThirdParty contained set_base32_alphabet +syn keyword ngxDirectiveThirdParty contained set_decode_base32 +syn keyword ngxDirectiveThirdParty contained set_encode_base64 +syn keyword ngxDirectiveThirdParty contained set_decode_base64 +syn keyword ngxDirectiveThirdParty contained set_encode_hex +syn keyword ngxDirectiveThirdParty contained set_decode_hex +syn keyword ngxDirectiveThirdParty contained set_sha1 +syn keyword ngxDirectiveThirdParty contained set_md5 +syn keyword ngxDirectiveThirdParty contained set_hmac_sha1 +syn keyword ngxDirectiveThirdParty contained set_random +syn keyword ngxDirectiveThirdParty contained set_secure_random_alphanum +syn keyword ngxDirectiveThirdParty contained set_secure_random_lcalpha +syn keyword ngxDirectiveThirdParty contained set_rotate +syn keyword ngxDirectiveThirdParty contained set_local_today +syn keyword ngxDirectiveThirdParty contained set_formatted_gmt_time +syn keyword ngxDirectiveThirdParty contained set_formatted_local_time " SFlow Module " A binary, random-sampling nginx module designed for: lightweight, centralized, continuous, real-time monitoring of very large and very busy web farms. -syn keyword ngxDirectiveThirdParty sflow +syn keyword ngxDirectiveThirdParty contained sflow " Shibboleth Module " Shibboleth auth request module for nginx -syn keyword ngxDirectiveThirdParty shib_request -syn keyword ngxDirectiveThirdParty shib_request_set -syn keyword ngxDirectiveThirdParty shib_request_use_headers +syn keyword ngxDirectiveThirdParty contained shib_request +syn keyword ngxDirectiveThirdParty contained shib_request_set +syn keyword ngxDirectiveThirdParty contained shib_request_use_headers " Slice Module " Nginx module for serving a file in slices (reverse byte-range) -" syn keyword ngxDirectiveThirdParty slice -syn keyword ngxDirectiveThirdParty slice_arg_begin -syn keyword ngxDirectiveThirdParty slice_arg_end -syn keyword ngxDirectiveThirdParty slice_header -syn keyword ngxDirectiveThirdParty slice_footer -syn keyword ngxDirectiveThirdParty slice_header_first -syn keyword ngxDirectiveThirdParty slice_footer_last +" syn keyword ngxDirectiveThirdParty contained slice +syn keyword ngxDirectiveThirdParty contained slice_arg_begin +syn keyword ngxDirectiveThirdParty contained slice_arg_end +syn keyword ngxDirectiveThirdParty contained slice_header +syn keyword ngxDirectiveThirdParty contained slice_footer +syn keyword ngxDirectiveThirdParty contained slice_header_first +syn keyword ngxDirectiveThirdParty contained slice_footer_last " SlowFS Cache Module " Module adding ability to cache static files. -syn keyword ngxDirectiveThirdParty slowfs_big_file_size -syn keyword ngxDirectiveThirdParty slowfs_cache -syn keyword ngxDirectiveThirdParty slowfs_cache_key -syn keyword ngxDirectiveThirdParty slowfs_cache_min_uses -syn keyword ngxDirectiveThirdParty slowfs_cache_path -syn keyword ngxDirectiveThirdParty slowfs_cache_purge -syn keyword ngxDirectiveThirdParty slowfs_cache_valid -syn keyword ngxDirectiveThirdParty slowfs_temp_path +syn keyword ngxDirectiveThirdParty contained slowfs_big_file_size +syn keyword ngxDirectiveThirdParty contained slowfs_cache +syn keyword ngxDirectiveThirdParty contained slowfs_cache_key +syn keyword ngxDirectiveThirdParty contained slowfs_cache_min_uses +syn keyword ngxDirectiveThirdParty contained slowfs_cache_path +syn keyword ngxDirectiveThirdParty contained slowfs_cache_purge +syn keyword ngxDirectiveThirdParty contained slowfs_cache_valid +syn keyword ngxDirectiveThirdParty contained slowfs_temp_path " Small Light Module " Dynamic Image Transformation Module For nginx. -syn keyword ngxDirectiveThirdParty small_light -syn keyword ngxDirectiveThirdParty small_light_getparam_mode -syn keyword ngxDirectiveThirdParty small_light_material_dir -syn keyword ngxDirectiveThirdParty small_light_pattern_define -syn keyword ngxDirectiveThirdParty small_light_radius_max -syn keyword ngxDirectiveThirdParty small_light_sigma_max -syn keyword ngxDirectiveThirdParty small_light_imlib2_temp_dir -syn keyword ngxDirectiveThirdParty small_light_buffer +syn keyword ngxDirectiveThirdParty contained small_light +syn keyword ngxDirectiveThirdParty contained small_light_getparam_mode +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 +syn keyword ngxDirectiveThirdParty contained small_light_imlib2_temp_dir +syn keyword ngxDirectiveThirdParty contained small_light_buffer " Sorted Querystring Filter Module " Nginx module to expose querystring parameters sorted in a variable to be used on cache_key as example -syn keyword ngxDirectiveThirdParty sorted_querystring_filter_parameter +syn keyword ngxDirectiveThirdParty contained sorted_querystring_filter_parameter " Sphinx2 Module " Nginx upstream module for Sphinx 2.x -syn keyword ngxDirectiveThirdParty sphinx2_pass -syn keyword ngxDirectiveThirdParty sphinx2_bind -syn keyword ngxDirectiveThirdParty sphinx2_connect_timeout -syn keyword ngxDirectiveThirdParty sphinx2_send_timeout -syn keyword ngxDirectiveThirdParty sphinx2_buffer_size -syn keyword ngxDirectiveThirdParty sphinx2_read_timeout -syn keyword ngxDirectiveThirdParty sphinx2_next_upstream +syn keyword ngxDirectiveThirdParty contained sphinx2_pass +syn keyword ngxDirectiveThirdParty contained sphinx2_bind +syn keyword ngxDirectiveThirdParty contained sphinx2_connect_timeout +syn keyword ngxDirectiveThirdParty contained sphinx2_send_timeout +syn keyword ngxDirectiveThirdParty contained sphinx2_buffer_size +syn keyword ngxDirectiveThirdParty contained sphinx2_read_timeout +syn keyword ngxDirectiveThirdParty contained sphinx2_next_upstream " HTTP SPNEGO auth Module " This module implements adds SPNEGO support to nginx(http://nginx.org). It currently supports only Kerberos authentication via GSSAPI -syn keyword ngxDirectiveThirdParty auth_gss -syn keyword ngxDirectiveThirdParty auth_gss_keytab -syn keyword ngxDirectiveThirdParty auth_gss_realm -syn keyword ngxDirectiveThirdParty auth_gss_service_name -syn keyword ngxDirectiveThirdParty auth_gss_authorized_principal -syn keyword ngxDirectiveThirdParty auth_gss_allow_basic_fallback +syn keyword ngxDirectiveThirdParty contained auth_gss +syn keyword ngxDirectiveThirdParty contained auth_gss_keytab +syn keyword ngxDirectiveThirdParty contained auth_gss_realm +syn keyword ngxDirectiveThirdParty contained auth_gss_service_name +syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal +syn keyword ngxDirectiveThirdParty contained auth_gss_allow_basic_fallback " SR Cache Module " Transparent subrequest-based caching layout for arbitrary nginx locations -syn keyword ngxDirectiveThirdParty srcache_fetch -syn keyword ngxDirectiveThirdParty srcache_fetch_skip -syn keyword ngxDirectiveThirdParty srcache_store -syn keyword ngxDirectiveThirdParty srcache_store_max_size -syn keyword ngxDirectiveThirdParty srcache_store_skip -syn keyword ngxDirectiveThirdParty srcache_store_statuses -syn keyword ngxDirectiveThirdParty srcache_store_ranges -syn keyword ngxDirectiveThirdParty srcache_header_buffer_size -syn keyword ngxDirectiveThirdParty srcache_store_hide_header -syn keyword ngxDirectiveThirdParty srcache_store_pass_header -syn keyword ngxDirectiveThirdParty srcache_methods -syn keyword ngxDirectiveThirdParty srcache_ignore_content_encoding -syn keyword ngxDirectiveThirdParty srcache_request_cache_control -syn keyword ngxDirectiveThirdParty srcache_response_cache_control -syn keyword ngxDirectiveThirdParty srcache_store_no_store -syn keyword ngxDirectiveThirdParty srcache_store_no_cache -syn keyword ngxDirectiveThirdParty srcache_store_private -syn keyword ngxDirectiveThirdParty srcache_default_expire -syn keyword ngxDirectiveThirdParty srcache_max_expire +syn keyword ngxDirectiveThirdParty contained srcache_fetch +syn keyword ngxDirectiveThirdParty contained srcache_fetch_skip +syn keyword ngxDirectiveThirdParty contained srcache_store +syn keyword ngxDirectiveThirdParty contained srcache_store_max_size +syn keyword ngxDirectiveThirdParty contained srcache_store_skip +syn keyword ngxDirectiveThirdParty contained srcache_store_statuses +syn keyword ngxDirectiveThirdParty contained srcache_store_ranges +syn keyword ngxDirectiveThirdParty contained srcache_header_buffer_size +syn keyword ngxDirectiveThirdParty contained srcache_store_hide_header +syn keyword ngxDirectiveThirdParty contained srcache_store_pass_header +syn keyword ngxDirectiveThirdParty contained srcache_methods +syn keyword ngxDirectiveThirdParty contained srcache_ignore_content_encoding +syn keyword ngxDirectiveThirdParty contained srcache_request_cache_control +syn keyword ngxDirectiveThirdParty contained srcache_response_cache_control +syn keyword ngxDirectiveThirdParty contained srcache_store_no_store +syn keyword ngxDirectiveThirdParty contained srcache_store_no_cache +syn keyword ngxDirectiveThirdParty contained srcache_store_private +syn keyword ngxDirectiveThirdParty contained srcache_default_expire +syn keyword ngxDirectiveThirdParty contained srcache_max_expire " SSSD Info Module " Retrives additional attributes from SSSD for current authentizated user -syn keyword ngxDirectiveThirdParty sssd_info -syn keyword ngxDirectiveThirdParty sssd_info_output_to -syn keyword ngxDirectiveThirdParty sssd_info_groups -syn keyword ngxDirectiveThirdParty sssd_info_group -syn keyword ngxDirectiveThirdParty sssd_info_group_separator -syn keyword ngxDirectiveThirdParty sssd_info_attributes -syn keyword ngxDirectiveThirdParty sssd_info_attribute -syn keyword ngxDirectiveThirdParty sssd_info_attribute_separator +syn keyword ngxDirectiveThirdParty contained sssd_info +syn keyword ngxDirectiveThirdParty contained sssd_info_output_to +syn keyword ngxDirectiveThirdParty contained sssd_info_groups +syn keyword ngxDirectiveThirdParty contained sssd_info_group +syn keyword ngxDirectiveThirdParty contained sssd_info_group_separator +syn keyword ngxDirectiveThirdParty contained sssd_info_attributes +syn keyword ngxDirectiveThirdParty contained sssd_info_attribute +syn keyword ngxDirectiveThirdParty contained sssd_info_attribute_separator " Static Etags Module " Generate etags for static content -syn keyword ngxDirectiveThirdParty FileETag +syn keyword ngxDirectiveThirdParty contained FileETag " Statsd Module " An nginx module for sending statistics to statsd -syn keyword ngxDirectiveThirdParty statsd_server -syn keyword ngxDirectiveThirdParty statsd_sample_rate -syn keyword ngxDirectiveThirdParty statsd_count -syn keyword ngxDirectiveThirdParty statsd_timing +syn keyword ngxDirectiveThirdParty contained statsd_server +syn keyword ngxDirectiveThirdParty contained statsd_sample_rate +syn keyword ngxDirectiveThirdParty contained statsd_count +syn keyword ngxDirectiveThirdParty contained statsd_timing " Sticky Module " Add a sticky cookie to be always forwarded to the same upstream server -" syn keyword ngxDirectiveThirdParty sticky +" syn keyword ngxDirectiveThirdParty contained sticky " Stream Echo Module " TCP/stream echo module for NGINX (a port of ngx_http_echo_module) -syn keyword ngxDirectiveThirdParty echo -syn keyword ngxDirectiveThirdParty echo_duplicate -syn keyword ngxDirectiveThirdParty echo_flush_wait -syn keyword ngxDirectiveThirdParty echo_sleep -syn keyword ngxDirectiveThirdParty echo_send_timeout -syn keyword ngxDirectiveThirdParty echo_read_bytes -syn keyword ngxDirectiveThirdParty echo_read_line -syn keyword ngxDirectiveThirdParty echo_request_data -syn keyword ngxDirectiveThirdParty echo_discard_request -syn keyword ngxDirectiveThirdParty echo_read_buffer_size -syn keyword ngxDirectiveThirdParty echo_read_timeout -syn keyword ngxDirectiveThirdParty echo_client_error_log_level -syn keyword ngxDirectiveThirdParty echo_lingering_close -syn keyword ngxDirectiveThirdParty echo_lingering_time -syn keyword ngxDirectiveThirdParty echo_lingering_timeout +syn keyword ngxDirectiveThirdParty contained echo +syn keyword ngxDirectiveThirdParty contained echo_duplicate +syn keyword ngxDirectiveThirdParty contained echo_flush_wait +syn keyword ngxDirectiveThirdParty contained echo_sleep +syn keyword ngxDirectiveThirdParty contained echo_send_timeout +syn keyword ngxDirectiveThirdParty contained echo_read_bytes +syn keyword ngxDirectiveThirdParty contained echo_read_line +syn keyword ngxDirectiveThirdParty contained echo_request_data +syn keyword ngxDirectiveThirdParty contained echo_discard_request +syn keyword ngxDirectiveThirdParty contained echo_read_buffer_size +syn keyword ngxDirectiveThirdParty contained echo_read_timeout +syn keyword ngxDirectiveThirdParty contained echo_client_error_log_level +syn keyword ngxDirectiveThirdParty contained echo_lingering_close +syn keyword ngxDirectiveThirdParty contained echo_lingering_time +syn keyword ngxDirectiveThirdParty contained echo_lingering_timeout " Stream Lua Module " Embed the power of Lua into Nginx stream/TCP Servers. -syn keyword ngxDirectiveThirdParty lua_resolver -syn keyword ngxDirectiveThirdParty lua_resolver_timeout -syn keyword ngxDirectiveThirdParty lua_lingering_close -syn keyword ngxDirectiveThirdParty lua_lingering_time -syn keyword ngxDirectiveThirdParty lua_lingering_timeout +syn keyword ngxDirectiveThirdParty contained lua_resolver +syn keyword ngxDirectiveThirdParty contained lua_resolver_timeout +syn keyword ngxDirectiveThirdParty contained lua_lingering_close +syn keyword ngxDirectiveThirdParty contained lua_lingering_time +syn keyword ngxDirectiveThirdParty contained lua_lingering_timeout " Stream Upsync Module " Sync upstreams from consul or others, dynamiclly modify backend-servers attribute(weight, max_fails,...), needn't reload nginx. -syn keyword ngxDirectiveThirdParty upsync -syn keyword ngxDirectiveThirdParty upsync_dump_path -syn keyword ngxDirectiveThirdParty upsync_lb -syn keyword ngxDirectiveThirdParty upsync_show +syn keyword ngxDirectiveThirdParty contained upsync +syn keyword ngxDirectiveThirdParty contained upsync_dump_path +syn keyword ngxDirectiveThirdParty contained upsync_lb +syn keyword ngxDirectiveThirdParty contained upsync_show " Strip Module " Whitespace remover. -syn keyword ngxDirectiveThirdParty strip +syn keyword ngxDirectiveThirdParty contained strip " Subrange Module " Split one big HTTP/Range request to multiple subrange requesets -syn keyword ngxDirectiveThirdParty subrange +syn keyword ngxDirectiveThirdParty contained subrange " Substitutions Module " A filter module which can do both regular expression and fixed string substitutions on response bodies. -syn keyword ngxDirectiveThirdParty subs_filter -syn keyword ngxDirectiveThirdParty subs_filter_types +syn keyword ngxDirectiveThirdParty contained subs_filter +syn keyword ngxDirectiveThirdParty contained subs_filter_types " Summarizer Module " Upstream nginx module to get summaries of documents using the summarizer daemon service -syn keyword ngxDirectiveThirdParty smrzr_filename -syn keyword ngxDirectiveThirdParty smrzr_ratio +syn keyword ngxDirectiveThirdParty contained smrzr_filename +syn keyword ngxDirectiveThirdParty contained smrzr_ratio " Supervisord Module " Module providing nginx with API to communicate with supervisord and manage (start/stop) backends on-demand. -syn keyword ngxDirectiveThirdParty supervisord -syn keyword ngxDirectiveThirdParty supervisord_inherit_backend_status -syn keyword ngxDirectiveThirdParty supervisord_name -syn keyword ngxDirectiveThirdParty supervisord_start -syn keyword ngxDirectiveThirdParty supervisord_stop +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 " Tarantool Upstream Module " Tarantool NginX upstream module (REST, JSON API, websockets, load balancing) -syn keyword ngxDirectiveThirdParty tnt_pass -syn keyword ngxDirectiveThirdParty tnt_http_methods -syn keyword ngxDirectiveThirdParty tnt_http_rest_methods -syn keyword ngxDirectiveThirdParty tnt_pass_http_request -syn keyword ngxDirectiveThirdParty tnt_pass_http_request_buffer_size -syn keyword ngxDirectiveThirdParty tnt_method -syn keyword ngxDirectiveThirdParty tnt_http_allowed_methods - experemental -syn keyword ngxDirectiveThirdParty tnt_send_timeout -syn keyword ngxDirectiveThirdParty tnt_read_timeout -syn keyword ngxDirectiveThirdParty tnt_buffer_size -syn keyword ngxDirectiveThirdParty tnt_next_upstream -syn keyword ngxDirectiveThirdParty tnt_connect_timeout -syn keyword ngxDirectiveThirdParty tnt_next_upstream -syn keyword ngxDirectiveThirdParty tnt_next_upstream_tries -syn keyword ngxDirectiveThirdParty tnt_next_upstream_timeout +syn keyword ngxDirectiveThirdParty contained tnt_pass +syn keyword ngxDirectiveThirdParty contained tnt_http_methods +syn keyword ngxDirectiveThirdParty contained tnt_http_rest_methods +syn keyword ngxDirectiveThirdParty contained tnt_pass_http_request +syn keyword ngxDirectiveThirdParty contained tnt_pass_http_request_buffer_size +syn keyword ngxDirectiveThirdParty contained tnt_method +syn keyword ngxDirectiveThirdParty contained tnt_http_allowed_methods - experemental +syn keyword ngxDirectiveThirdParty contained tnt_send_timeout +syn keyword ngxDirectiveThirdParty contained tnt_read_timeout +syn keyword ngxDirectiveThirdParty contained tnt_buffer_size +syn keyword ngxDirectiveThirdParty contained tnt_next_upstream +syn keyword ngxDirectiveThirdParty contained tnt_connect_timeout +syn keyword ngxDirectiveThirdParty contained tnt_next_upstream +syn keyword ngxDirectiveThirdParty contained tnt_next_upstream_tries +syn keyword ngxDirectiveThirdParty contained tnt_next_upstream_timeout " TCP Proxy Module " Add the feature of tcp proxy with nginx, with health check and status monitor -syn keyword ngxDirectiveBlock tcp -" syn keyword ngxDirectiveThirdParty server -" syn keyword ngxDirectiveThirdParty listen -" syn keyword ngxDirectiveThirdParty allow -" syn keyword ngxDirectiveThirdParty deny -" syn keyword ngxDirectiveThirdParty so_keepalive -" syn keyword ngxDirectiveThirdParty tcp_nodelay -" syn keyword ngxDirectiveThirdParty timeout -" syn keyword ngxDirectiveThirdParty server_name -" syn keyword ngxDirectiveThirdParty resolver -" syn keyword ngxDirectiveThirdParty resolver_timeout -" syn keyword ngxDirectiveThirdParty upstream -syn keyword ngxDirectiveThirdParty check -syn keyword ngxDirectiveThirdParty check_http_send -syn keyword ngxDirectiveThirdParty check_http_expect_alive -syn keyword ngxDirectiveThirdParty check_smtp_send -syn keyword ngxDirectiveThirdParty check_smtp_expect_alive -syn keyword ngxDirectiveThirdParty check_shm_size -syn keyword ngxDirectiveThirdParty check_status -" syn keyword ngxDirectiveThirdParty ip_hash -" syn keyword ngxDirectiveThirdParty proxy_pass -" syn keyword ngxDirectiveThirdParty proxy_buffer -" syn keyword ngxDirectiveThirdParty proxy_connect_timeout -" syn keyword ngxDirectiveThirdParty proxy_read_timeout -syn keyword ngxDirectiveThirdParty proxy_write_timeout +syn keyword ngxDirectiveBlock contained tcp +" syn keyword ngxDirectiveThirdParty contained server +" syn keyword ngxDirectiveThirdParty contained listen +" syn keyword ngxDirectiveThirdParty contained allow +" syn keyword ngxDirectiveThirdParty contained deny +" syn keyword ngxDirectiveThirdParty contained so_keepalive +" syn keyword ngxDirectiveThirdParty contained tcp_nodelay +" syn keyword ngxDirectiveThirdParty contained timeout +" syn keyword ngxDirectiveThirdParty contained server_name +" syn keyword ngxDirectiveThirdParty contained resolver +" syn keyword ngxDirectiveThirdParty contained resolver_timeout +" syn keyword ngxDirectiveThirdParty contained upstream +syn keyword ngxDirectiveThirdParty contained check +syn keyword ngxDirectiveThirdParty contained check_http_send +syn keyword ngxDirectiveThirdParty contained check_http_expect_alive +syn keyword ngxDirectiveThirdParty contained check_smtp_send +syn keyword ngxDirectiveThirdParty contained check_smtp_expect_alive +syn keyword ngxDirectiveThirdParty contained check_shm_size +syn keyword ngxDirectiveThirdParty contained check_status +" syn keyword ngxDirectiveThirdParty contained ip_hash +" syn keyword ngxDirectiveThirdParty contained proxy_pass +" syn keyword ngxDirectiveThirdParty contained proxy_buffer +" syn keyword ngxDirectiveThirdParty contained proxy_connect_timeout +" syn keyword ngxDirectiveThirdParty contained proxy_read_timeout +syn keyword ngxDirectiveThirdParty contained proxy_write_timeout " Testcookie Module " NGINX module for L7 DDoS attack mitigation -syn keyword ngxDirectiveThirdParty testcookie -syn keyword ngxDirectiveThirdParty testcookie_name -syn keyword ngxDirectiveThirdParty testcookie_domain -syn keyword ngxDirectiveThirdParty testcookie_expires -syn keyword ngxDirectiveThirdParty testcookie_path -syn keyword ngxDirectiveThirdParty testcookie_secret -syn keyword ngxDirectiveThirdParty testcookie_session -syn keyword ngxDirectiveThirdParty testcookie_arg -syn keyword ngxDirectiveThirdParty testcookie_max_attempts -syn keyword ngxDirectiveThirdParty testcookie_p3p -syn keyword ngxDirectiveThirdParty testcookie_fallback -syn keyword ngxDirectiveThirdParty testcookie_whitelist -syn keyword ngxDirectiveThirdParty testcookie_pass -syn keyword ngxDirectiveThirdParty testcookie_redirect_via_refresh -syn keyword ngxDirectiveThirdParty testcookie_refresh_template -syn keyword ngxDirectiveThirdParty testcookie_refresh_status -syn keyword ngxDirectiveThirdParty testcookie_deny_keepalive -syn keyword ngxDirectiveThirdParty testcookie_get_only -syn keyword ngxDirectiveThirdParty testcookie_https_location -syn keyword ngxDirectiveThirdParty testcookie_refresh_encrypt_cookie -syn keyword ngxDirectiveThirdParty testcookie_refresh_encrypt_cookie_key -syn keyword ngxDirectiveThirdParty testcookie_refresh_encrypt_iv -syn keyword ngxDirectiveThirdParty testcookie_internal -syn keyword ngxDirectiveThirdParty testcookie_httponly_flag -syn keyword ngxDirectiveThirdParty testcookie_secure_flag +syn keyword ngxDirectiveThirdParty contained testcookie +syn keyword ngxDirectiveThirdParty contained testcookie_name +syn keyword ngxDirectiveThirdParty contained testcookie_domain +syn keyword ngxDirectiveThirdParty contained testcookie_expires +syn keyword ngxDirectiveThirdParty contained testcookie_path +syn keyword ngxDirectiveThirdParty contained testcookie_secret +syn keyword ngxDirectiveThirdParty contained testcookie_session +syn keyword ngxDirectiveThirdParty contained testcookie_arg +syn keyword ngxDirectiveThirdParty contained testcookie_max_attempts +syn keyword ngxDirectiveThirdParty contained testcookie_p3p +syn keyword ngxDirectiveThirdParty contained testcookie_fallback +syn keyword ngxDirectiveThirdParty contained testcookie_whitelist +syn keyword ngxDirectiveThirdParty contained testcookie_pass +syn keyword ngxDirectiveThirdParty contained testcookie_redirect_via_refresh +syn keyword ngxDirectiveThirdParty contained testcookie_refresh_template +syn keyword ngxDirectiveThirdParty contained testcookie_refresh_status +syn keyword ngxDirectiveThirdParty contained testcookie_deny_keepalive +syn keyword ngxDirectiveThirdParty contained testcookie_get_only +syn keyword ngxDirectiveThirdParty contained testcookie_https_location +syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie +syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_cookie_key +syn keyword ngxDirectiveThirdParty contained testcookie_refresh_encrypt_iv +syn keyword ngxDirectiveThirdParty contained testcookie_internal +syn keyword ngxDirectiveThirdParty contained testcookie_httponly_flag +syn keyword ngxDirectiveThirdParty contained testcookie_secure_flag " Types Filter Module " Change the `Content-Type` output header depending on an extension variable according to a condition specified in the 'if' clause. -syn keyword ngxDirectiveThirdParty types_filter -syn keyword ngxDirectiveThirdParty types_filter_use_default +syn keyword ngxDirectiveThirdParty contained types_filter +syn keyword ngxDirectiveThirdParty contained types_filter_use_default " Unzip Module " Enabling fetching of files that are stored in zipped archives. -syn keyword ngxDirectiveThirdParty file_in_unzip_archivefile -syn keyword ngxDirectiveThirdParty file_in_unzip_extract -syn keyword ngxDirectiveThirdParty file_in_unzip +syn keyword ngxDirectiveThirdParty contained file_in_unzip_archivefile +syn keyword ngxDirectiveThirdParty contained file_in_unzip_extract +syn keyword ngxDirectiveThirdParty contained file_in_unzip " Upload Progress Module " An upload progress system, that monitors RFC1867 POST upload as they are transmitted to upstream servers -syn keyword ngxDirectiveThirdParty upload_progress -syn keyword ngxDirectiveThirdParty track_uploads -syn keyword ngxDirectiveThirdParty report_uploads -syn keyword ngxDirectiveThirdParty upload_progress_content_type -syn keyword ngxDirectiveThirdParty upload_progress_header -syn keyword ngxDirectiveThirdParty upload_progress_jsonp_parameter -syn keyword ngxDirectiveThirdParty upload_progress_json_output -syn keyword ngxDirectiveThirdParty upload_progress_jsonp_output -syn keyword ngxDirectiveThirdParty upload_progress_template +syn keyword ngxDirectiveThirdParty contained upload_progress +syn keyword ngxDirectiveThirdParty contained track_uploads +syn keyword ngxDirectiveThirdParty contained report_uploads +syn keyword ngxDirectiveThirdParty contained upload_progress_content_type +syn keyword ngxDirectiveThirdParty contained upload_progress_header +syn keyword ngxDirectiveThirdParty contained upload_progress_jsonp_parameter +syn keyword ngxDirectiveThirdParty contained upload_progress_json_output +syn keyword ngxDirectiveThirdParty contained upload_progress_jsonp_output +syn keyword ngxDirectiveThirdParty contained upload_progress_template " Upload Module " Parses request body storing all files being uploaded to a directory specified by upload_store directive -syn keyword ngxDirectiveThirdParty upload_pass -syn keyword ngxDirectiveThirdParty upload_resumable -syn keyword ngxDirectiveThirdParty upload_store -syn keyword ngxDirectiveThirdParty upload_state_store -syn keyword ngxDirectiveThirdParty upload_store_access -syn keyword ngxDirectiveThirdParty upload_set_form_field -syn keyword ngxDirectiveThirdParty upload_aggregate_form_field -syn keyword ngxDirectiveThirdParty upload_pass_form_field -syn keyword ngxDirectiveThirdParty upload_cleanup -syn keyword ngxDirectiveThirdParty upload_buffer_size -syn keyword ngxDirectiveThirdParty upload_max_part_header_len -syn keyword ngxDirectiveThirdParty upload_max_file_size -syn keyword ngxDirectiveThirdParty upload_limit_rate -syn keyword ngxDirectiveThirdParty upload_max_output_body_len -syn keyword ngxDirectiveThirdParty upload_tame_arrays -syn keyword ngxDirectiveThirdParty upload_pass_args +syn keyword ngxDirectiveThirdParty contained upload_pass +syn keyword ngxDirectiveThirdParty contained upload_resumable +syn keyword ngxDirectiveThirdParty contained upload_store +syn keyword ngxDirectiveThirdParty contained upload_state_store +syn keyword ngxDirectiveThirdParty contained upload_store_access +syn keyword ngxDirectiveThirdParty contained upload_set_form_field +syn keyword ngxDirectiveThirdParty contained upload_aggregate_form_field +syn keyword ngxDirectiveThirdParty contained upload_pass_form_field +syn keyword ngxDirectiveThirdParty contained upload_cleanup +syn keyword ngxDirectiveThirdParty contained upload_buffer_size +syn keyword ngxDirectiveThirdParty contained upload_max_part_header_len +syn keyword ngxDirectiveThirdParty contained upload_max_file_size +syn keyword ngxDirectiveThirdParty contained upload_limit_rate +syn keyword ngxDirectiveThirdParty contained upload_max_output_body_len +syn keyword ngxDirectiveThirdParty contained upload_tame_arrays +syn keyword ngxDirectiveThirdParty contained upload_pass_args " Upstream Fair Module " The fair load balancer module for nginx http://nginx.localdomain.pl -syn keyword ngxDirectiveThirdParty fair -syn keyword ngxDirectiveThirdParty upstream_fair_shm_size +syn keyword ngxDirectiveThirdParty contained fair +syn keyword ngxDirectiveThirdParty contained upstream_fair_shm_size " Upstream Hash Module (DEPRECATED) " Provides simple upstream load distribution by hashing a configurable variable. -" syn keyword ngxDirectiveDeprecated hash -syn keyword ngxDirectiveDeprecated hash_again +" syn keyword ngxDirectiveDeprecated contained hash +syn keyword ngxDirectiveDeprecated contained hash_again " Upstream Domain Resolve Module " A load-balancer that resolves an upstream domain name asynchronously. -syn keyword ngxDirectiveThirdParty jdomain +syn keyword ngxDirectiveThirdParty contained jdomain " Upsync Module " Sync upstreams from consul or others, dynamiclly modify backend-servers attribute(weight, max_fails,...), needn't reload nginx -syn keyword ngxDirectiveThirdParty upsync -syn keyword ngxDirectiveThirdParty upsync_dump_path -syn keyword ngxDirectiveThirdParty upsync_lb -syn keyword ngxDirectiveThirdParty upstream_show +syn keyword ngxDirectiveThirdParty contained upsync +syn keyword ngxDirectiveThirdParty contained upsync_dump_path +syn keyword ngxDirectiveThirdParty contained upsync_lb +syn keyword ngxDirectiveThirdParty contained upstream_show " URL Module " Nginx url encoding converting module -syn keyword ngxDirectiveThirdParty url_encoding_convert -syn keyword ngxDirectiveThirdParty url_encoding_convert_from -syn keyword ngxDirectiveThirdParty url_encoding_convert_to +syn keyword ngxDirectiveThirdParty contained url_encoding_convert +syn keyword ngxDirectiveThirdParty contained url_encoding_convert_from +syn keyword ngxDirectiveThirdParty contained url_encoding_convert_to " User Agent Module " Match browsers and crawlers -syn keyword ngxDirectiveThirdParty user_agent +syn keyword ngxDirectiveThirdParty contained user_agent " Upstrema Ketama Chash Module " Nginx load-balancer module implementing ketama consistent hashing. -syn keyword ngxDirectiveThirdParty ketama_chash +syn keyword ngxDirectiveThirdParty contained ketama_chash " Video Thumbextractor Module " Extract thumbs from a video file -syn keyword ngxDirectiveThirdParty video_thumbextractor -syn keyword ngxDirectiveThirdParty video_thumbextractor_video_filename -syn keyword ngxDirectiveThirdParty video_thumbextractor_video_second -syn keyword ngxDirectiveThirdParty video_thumbextractor_image_width -syn keyword ngxDirectiveThirdParty video_thumbextractor_image_height -syn keyword ngxDirectiveThirdParty video_thumbextractor_only_keyframe -syn keyword ngxDirectiveThirdParty video_thumbextractor_next_time -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_rows -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_cols -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_max_rows -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_max_cols -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_sample_interval -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_color -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_margin -syn keyword ngxDirectiveThirdParty video_thumbextractor_tile_padding -syn keyword ngxDirectiveThirdParty video_thumbextractor_threads -syn keyword ngxDirectiveThirdParty video_thumbextractor_processes_per_worker +syn keyword ngxDirectiveThirdParty contained video_thumbextractor +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_video_filename +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_video_second +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_image_width +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_image_height +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_only_keyframe +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_next_time +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_rows +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_cols +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_max_rows +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_max_cols +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_sample_interval +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_color +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_margin +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_tile_padding +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_threads +syn keyword ngxDirectiveThirdParty contained video_thumbextractor_processes_per_worker " Eval Module " Module for nginx web server evaluates response of proxy or memcached module into variables. -syn keyword ngxDirectiveThirdParty eval -syn keyword ngxDirectiveThirdParty eval_escalate -syn keyword ngxDirectiveThirdParty eval_override_content_type +syn keyword ngxDirectiveThirdParty contained eval +syn keyword ngxDirectiveThirdParty contained eval_escalate +syn keyword ngxDirectiveThirdParty contained eval_override_content_type " VTS Module " Nginx virtual host traffic status module -syn keyword ngxDirectiveThirdParty vhost_traffic_status -syn keyword ngxDirectiveThirdParty vhost_traffic_status_zone -syn keyword ngxDirectiveThirdParty vhost_traffic_status_display -syn keyword ngxDirectiveThirdParty vhost_traffic_status_display_format -syn keyword ngxDirectiveThirdParty vhost_traffic_status_display_jsonp -syn keyword ngxDirectiveThirdParty vhost_traffic_status_filter -syn keyword ngxDirectiveThirdParty vhost_traffic_status_filter_by_host -syn keyword ngxDirectiveThirdParty vhost_traffic_status_filter_by_set_key -syn keyword ngxDirectiveThirdParty vhost_traffic_status_filter_check_duplicate -syn keyword ngxDirectiveThirdParty vhost_traffic_status_limit -syn keyword ngxDirectiveThirdParty vhost_traffic_status_limit_traffic -syn keyword ngxDirectiveThirdParty vhost_traffic_status_limit_traffic_by_set_key -syn keyword ngxDirectiveThirdParty vhost_traffic_status_limit_check_duplicate +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_zone +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_display +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_display_format +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_display_jsonp +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_by_host +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_by_set_key +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_check_duplicate +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_traffic +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_traffic_by_set_key +syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_check_duplicate " XSS Module " Native support for cross-site scripting (XSS) in an nginx. -syn keyword ngxDirectiveThirdParty xss_get -syn keyword ngxDirectiveThirdParty xss_callback_arg -syn keyword ngxDirectiveThirdParty xss_override_status -syn keyword ngxDirectiveThirdParty xss_check_status -syn keyword ngxDirectiveThirdParty xss_input_types +syn keyword ngxDirectiveThirdParty contained xss_get +syn keyword ngxDirectiveThirdParty contained xss_callback_arg +syn keyword ngxDirectiveThirdParty contained xss_override_status +syn keyword ngxDirectiveThirdParty contained xss_check_status +syn keyword ngxDirectiveThirdParty contained xss_input_types " ZIP Module " ZIP archiver for nginx @@ -2122,15 +2152,17 @@ syn keyword ngxDirectiveThirdParty xss_input_types " highlight hi link ngxComment Comment +hi link ngxParamComment Comment +hi link ngxListenComment Comment hi link ngxVariable Identifier -hi link ngxVariableBlock Identifier hi link ngxVariableString PreProc -hi link ngxBlock Normal hi link ngxString String +hi link ngxListenString String hi link ngxBoolean Boolean hi link ngxDirectiveBlock Statement hi link ngxDirectiveImportant Type +hi link ngxDirectiveListen Type hi link ngxDirectiveControl Keyword hi link ngxDirectiveError Constant hi link ngxDirectiveDeprecated Error @@ -2138,7 +2170,5 @@ hi link ngxDirective Identifier hi link ngxDirectiveThirdParty Special hi link ngxListenOptions Keyword -hi link ngxMailProtocol Keyword -hi link ngxSSLProtocol Keyword let b:current_syntax = "nginx" diff --git a/src/core/nginx.h b/src/core/nginx.h index 3d6579c..8cc2d80 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013000 -#define NGINX_VERSION "1.13.0" +#define nginx_version 1013001 +#define NGINX_VERSION "1.13.1" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 2af2876..ec4692b 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -1345,6 +1345,49 @@ ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, } +ngx_int_t +ngx_tcp_nodelay(ngx_connection_t *c) +{ + int tcp_nodelay; + + if (c->tcp_nodelay != NGX_TCP_NODELAY_UNSET) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) + == -1) + { +#if (NGX_SOLARIS) + if (c->log_error == NGX_ERROR_INFO) { + + /* Solaris returns EINVAL if a socket has been shut down */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; + + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + + c->log_error = NGX_ERROR_INFO; + + return NGX_ERROR; + } +#endif + + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + return NGX_ERROR; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + + return NGX_OK; +} + + ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) { diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 1d3e3a3..e4dfe58 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -214,6 +214,7 @@ void ngx_close_connection(ngx_connection_t *c); void ngx_close_idle_connections(ngx_cycle_t *cycle); ngx_int_t ngx_connection_local_sockaddr(ngx_connection_t *c, ngx_str_t *s, ngx_uint_t port); +ngx_int_t ngx_tcp_nodelay(ngx_connection_t *c); ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text); ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log); diff --git a/src/core/ngx_murmurhash.c b/src/core/ngx_murmurhash.c index c31e0e0..5ade658 100644 --- a/src/core/ngx_murmurhash.c +++ b/src/core/ngx_murmurhash.c @@ -35,8 +35,10 @@ ngx_murmur_hash2(u_char *data, size_t len) switch (len) { case 3: h ^= data[2] << 16; + /* fall through */ case 2: h ^= data[1] << 8; + /* fall through */ case 1: h ^= data[0]; h *= 0x5bd1e995; diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 1fce2e8..87447d0 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -238,7 +238,7 @@ ngx_event_accept(ngx_event_t *ev) if (ev->deferred_accept) { rev->ready = 1; -#if (NGX_HAVE_KQUEUE) +#if (NGX_HAVE_KQUEUE || NGX_HAVE_EPOLLRDHUP) rev->available = 1; #endif } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index fdbd0c9..2c4e114 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1300,7 +1300,7 @@ ngx_ssl_handshake(ngx_connection_t *c) #ifdef SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS /* initial handshake done, disable renegotiation (CVE-2009-3555) */ - if (c->ssl->connection->s3) { + if (c->ssl->connection->s3 && SSL_is_server(c->ssl->connection)) { c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS; } diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c index c553e46..7355de9 100644 --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -309,28 +309,22 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_http_access_rule_un_t *rule_un; #endif + all = 0; ngx_memzero(&cidr, sizeof(ngx_cidr_t)); value = cf->args->elts; - all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); - - if (!all) { + if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { + all = 1; #if (NGX_HAVE_UNIX_DOMAIN) - - if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { - cidr.family = AF_UNIX; - rc = NGX_OK; - - } else { - rc = ngx_ptocidr(&value[1], &cidr); - } - -#else - rc = ngx_ptocidr(&value[1], &cidr); + } else if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { + cidr.family = AF_UNIX; #endif + } else { + rc = ngx_ptocidr(&value[1], &cidr); + if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[1]); diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 06c1973..741e577 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1878,6 +1878,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) p = ngx_pnalloc(r->pool, size); if (p == NULL) { + h->hash = 0; return NGX_ERROR; } @@ -1900,6 +1901,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "invalid header after joining " "FastCGI records"); + h->hash = 0; return NGX_ERROR; } @@ -1925,6 +1927,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { + h->hash = 0; return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 0fee2c2..839d479 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1798,6 +1798,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) h->key.data = ngx_pnalloc(r->pool, h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { + h->hash = 0; return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index 5e3355c..e1839e6 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -317,9 +317,15 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_realip_loc_conf_t *rlcf = conf; - ngx_int_t rc; - ngx_str_t *value; - ngx_cidr_t *cidr; + ngx_int_t rc; + ngx_str_t *value; + ngx_url_t u; + ngx_cidr_t c, *cidr; + ngx_uint_t i; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif value = cf->args->elts; @@ -331,31 +337,78 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - cidr = ngx_array_push(rlcf->from); - if (cidr == NULL) { - return NGX_CONF_ERROR; - } - #if (NGX_HAVE_UNIX_DOMAIN) if (ngx_strcmp(value[1].data, "unix:") == 0) { + cidr = ngx_array_push(rlcf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + cidr->family = AF_UNIX; return NGX_CONF_OK; } #endif - rc = ngx_ptocidr(&value[1], cidr); + rc = ngx_ptocidr(&value[1], &c); + + if (rc != NGX_ERROR) { + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", + &value[1]); + } + + cidr = ngx_array_push(rlcf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + *cidr = c; + + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + u.host = value[1]; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in set_real_ip_from \"%V\"", + u.err, &u.host); + } - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", - &value[1]); 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[1]); + cidr = ngx_array_push_n(rlcf->from, u.naddrs); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(cidr, u.naddrs * sizeof(ngx_cidr_t)); + + for (i = 0; i < u.naddrs; i++) { + cidr[i].family = u.addrs[i].sockaddr->sa_family; + + switch (cidr[i].family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) u.addrs[i].sockaddr; + cidr[i].u.in6.addr = sin6->sin6_addr; + ngx_memset(cidr[i].u.in6.mask.s6_addr, 0xff, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) u.addrs[i].sockaddr; + cidr[i].u.in.addr = sin->sin_addr.s_addr; + cidr[i].u.in.mask = 0xffffffff; + break; + } } 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 d1e37dd..9204af4 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1040,6 +1040,7 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { + h->hash = 0; return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 26443bb..a2bec4c 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1244,6 +1244,7 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) h->key.len + 1 + h->value.len + 1 + h->key.len); if (h->key.data == NULL) { + h->hash = 0; return NGX_ERROR; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index af67b7f..7e40e78 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2518,6 +2518,7 @@ ngx_http_subrequest(ngx_http_request_t *r, sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0; sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0; + sr->background = (flags & NGX_HTTP_SUBREQUEST_BACKGROUND) != 0; sr->unparsed_uri = r->unparsed_uri; sr->method_name = ngx_http_core_get_method; @@ -2531,29 +2532,31 @@ ngx_http_subrequest(ngx_http_request_t *r, sr->read_event_handler = ngx_http_request_empty_handler; sr->write_event_handler = ngx_http_handler; - if (c->data == r && r->postponed == NULL) { - c->data = sr; - } - sr->variables = r->variables; sr->log_handler = r->log_handler; - pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); - if (pr == NULL) { - return NGX_ERROR; - } + if (!sr->background) { + if (c->data == r && r->postponed == NULL) { + c->data = sr; + } - pr->request = sr; - pr->out = NULL; - pr->next = NULL; + pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t)); + if (pr == NULL) { + return NGX_ERROR; + } - if (r->postponed) { - for (p = r->postponed; p->next; p = p->next) { /* void */ } - p->next = pr; + pr->request = sr; + pr->out = NULL; + pr->next = NULL; - } else { - r->postponed = pr; + if (r->postponed) { + for (p = r->postponed; p->next; p = p->next) { /* void */ } + p->next = pr; + + } else { + r->postponed = pr; + } } sr->internal = 1; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index b635b35..a823c51 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -1700,13 +1700,14 @@ ngx_http_file_cache_cleanup(void *data) static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) { - u_char *name; + u_char *name, *p; size_t len; time_t wait; ngx_uint_t tries; ngx_path_t *path; - ngx_queue_t *q; + ngx_queue_t *q, *sentinel; ngx_http_file_cache_node_t *fcn; + u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, "http file cache forced expire"); @@ -1723,13 +1724,21 @@ ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) wait = 10; tries = 20; + sentinel = NULL; ngx_shmtx_lock(&cache->shpool->mutex); - for (q = ngx_queue_last(&cache->sh->queue); - q != ngx_queue_sentinel(&cache->sh->queue); - q = ngx_queue_prev(q)) - { + for ( ;; ) { + if (ngx_queue_empty(&cache->sh->queue)) { + break; + } + + q = ngx_queue_last(&cache->sh->queue); + + if (q == sentinel) { + break; + } + fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, @@ -1740,15 +1749,37 @@ ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) if (fcn->count == 0) { ngx_http_file_cache_delete(cache, q, name); wait = 0; - - } else { - if (--tries) { - continue; - } - - 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); + (void) ngx_hex_dump(p, fcn->key, len); + + /* + * abnormally exited workers may leave locked cache entries, + * and although it may be safe to remove them completely, + * we prefer to just move them to the top of the inactive queue + */ + + ngx_queue_remove(q); + fcn->expire = ngx_time() + cache->inactive; + ngx_queue_insert_head(&cache->sh->queue, &fcn->queue); + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "ignore long locked inactive cache entry %*s, count:%d", + (size_t) 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); + + if (sentinel == NULL) { + sentinel = q; + } + + if (--tries) { + continue; + } + + wait = 1; break; } diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 5fc7e1f..9b89405 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -119,7 +119,7 @@ static ngx_str_t ngx_http_status_lines[] = { ngx_string("502 Bad Gateway"), ngx_string("503 Service Temporarily Unavailable"), ngx_string("504 Gateway Time-out"), - ngx_null_string, /* "505 HTTP Version Not Supported" */ + ngx_string("505 HTTP Version Not Supported"), ngx_null_string, /* "506 Variant Also Negotiates" */ ngx_string("507 Insufficient Storage"), diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 9f99473..e8e5156 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -723,6 +723,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) } r->http_major = ch - '0'; + + if (r->http_major > 1) { + return NGX_HTTP_PARSE_INVALID_VERSION; + } + state = sw_major_digit; break; @@ -737,11 +742,12 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - if (r->http_major > 99) { - return NGX_HTTP_PARSE_INVALID_REQUEST; + r->http_major = r->http_major * 10 + ch - '0'; + + if (r->http_major > 1) { + return NGX_HTTP_PARSE_INVALID_VERSION; } - r->http_major = r->http_major * 10 + ch - '0'; break; /* first digit of minor HTTP version */ @@ -1390,6 +1396,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) goto done; case '+': r->plus_in_uri = 1; + /* fall through */ default: state = sw_usual; *u++ = ch; @@ -1431,6 +1438,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) goto done; case '+': r->plus_in_uri = 1; + /* fall through */ default: state = sw_usual; *u++ = ch; @@ -1478,6 +1486,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) goto done; case '+': r->plus_in_uri = 1; + /* fall through */ default: state = sw_usual; *u++ = ch; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 476f039..cc3722f 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -72,6 +72,9 @@ static char *ngx_http_client_errors[] = { /* NGX_HTTP_PARSE_INVALID_REQUEST */ "client sent invalid request", + /* NGX_HTTP_PARSE_INVALID_VERSION */ + "client sent invalid version", + /* NGX_HTTP_PARSE_INVALID_09_METHOD */ "client sent invalid method in HTTP/0.9 request" }; @@ -620,14 +623,15 @@ ngx_http_create_request(ngx_connection_t *c) static void ngx_http_ssl_handshake(ngx_event_t *rev) { - u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1]; - size_t size; - ssize_t n; - ngx_err_t err; - ngx_int_t rc; - ngx_connection_t *c; - ngx_http_connection_t *hc; - ngx_http_ssl_srv_conf_t *sscf; + u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1]; + size_t size; + ssize_t n; + ngx_err_t err; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_connection_t *hc; + ngx_http_ssl_srv_conf_t *sscf; + ngx_http_core_loc_conf_t *clcf; c = rev->data; hc = c->data; @@ -709,6 +713,14 @@ ngx_http_ssl_handshake(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0, "https ssl handshake: 0x%02Xd", buf[0]); + clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, + ngx_http_core_module); + + if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); @@ -1036,7 +1048,14 @@ ngx_http_process_request_line(ngx_event_t *rev) ngx_log_error(NGX_LOG_INFO, c->log, 0, ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]); - ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + + if (rc == NGX_HTTP_PARSE_INVALID_VERSION) { + ngx_http_finalize_request(r, NGX_HTTP_VERSION_NOT_SUPPORTED); + + } else { + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + } + return; } @@ -2312,10 +2331,6 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) return; } - if (r->main->blocked) { - r->write_event_handler = ngx_http_request_finalizer; - } - ngx_http_terminate_request(r, rc); return; } @@ -2347,6 +2362,26 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) } if (r != r->main) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->background) { + if (!r->logged) { + if (clcf->log_subrequest) { + ngx_http_log_request(r); + } + + r->logged = 1; + + } else { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "subrequest: \"%V?%V\" logged again", + &r->uri, &r->args); + } + + r->done = 1; + ngx_http_finalize_connection(r); + return; + } if (r->buffered || r->postponed) { @@ -2364,9 +2399,6 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) r->main->count--; if (!r->logged) { - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (clcf->log_subrequest) { ngx_http_log_request(r); } @@ -2413,7 +2445,7 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) return; } - if (r->buffered || c->buffered || r->postponed || r->blocked) { + if (r->buffered || c->buffered || r->postponed) { if (ngx_http_set_write_handler(r) != NGX_OK) { ngx_http_terminate_request(r, 0); @@ -2430,6 +2462,8 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc) } r->done = 1; + + r->read_event_handler = ngx_http_block_reading; r->write_event_handler = ngx_http_request_empty_handler; if (!r->post_action) { @@ -2492,6 +2526,8 @@ ngx_http_terminate_request(ngx_http_request_t *r, ngx_int_t rc) if (mr->write_event_handler) { if (mr->blocked) { + r->connection->error = 1; + r->write_event_handler = ngx_http_request_finalizer; return; } @@ -2548,6 +2584,8 @@ ngx_http_finalize_connection(ngx_http_request_t *r) return; } + r = r->main; + if (r->reading_body) { r->keepalive = 0; r->lingering_close = 1; @@ -3030,30 +3068,9 @@ ngx_http_set_keepalive(ngx_http_request_t *r) tcp_nodelay = 1; } - if (tcp_nodelay - && clcf->tcp_nodelay - && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) - { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) - == -1) - { -#if (NGX_SOLARIS) - /* Solaris returns EINVAL if a socket has been shut down */ - c->log_error = NGX_ERROR_IGNORE_EINVAL; -#endif - - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - - c->log_error = NGX_ERROR_INFO; - ngx_http_close_connection(c); - return; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + if (tcp_nodelay && clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + ngx_http_close_connection(c); + return; } #if 0 diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 2c77f93..283c582 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -54,15 +54,17 @@ #define NGX_HTTP_CLIENT_ERROR 10 #define NGX_HTTP_PARSE_INVALID_METHOD 10 #define NGX_HTTP_PARSE_INVALID_REQUEST 11 -#define NGX_HTTP_PARSE_INVALID_09_METHOD 12 +#define NGX_HTTP_PARSE_INVALID_VERSION 12 +#define NGX_HTTP_PARSE_INVALID_09_METHOD 13 -#define NGX_HTTP_PARSE_INVALID_HEADER 13 +#define NGX_HTTP_PARSE_INVALID_HEADER 14 /* unused 1 */ #define NGX_HTTP_SUBREQUEST_IN_MEMORY 2 #define NGX_HTTP_SUBREQUEST_WAITED 4 #define NGX_HTTP_SUBREQUEST_CLONE 8 +#define NGX_HTTP_SUBREQUEST_BACKGROUND 16 #define NGX_HTTP_LOG_UNSAFE 1 @@ -136,6 +138,7 @@ #define NGX_HTTP_BAD_GATEWAY 502 #define NGX_HTTP_SERVICE_UNAVAILABLE 503 #define NGX_HTTP_GATEWAY_TIME_OUT 504 +#define NGX_HTTP_VERSION_NOT_SUPPORTED 505 #define NGX_HTTP_INSUFFICIENT_STORAGE 507 @@ -484,7 +487,6 @@ struct ngx_http_request_s { #if (NGX_HTTP_CACHE) unsigned cached:1; - unsigned cache_updater:1; #endif #if (NGX_HTTP_GZIP) @@ -541,6 +543,7 @@ struct ngx_http_request_s { unsigned stat_writing:1; unsigned stat_processing:1; + unsigned background:1; unsigned health_check:1; /* used to parse HTTP headers */ diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c index c4c1305..2c1ff17 100644 --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -321,6 +321,14 @@ static char ngx_http_error_504_page[] = ; +static char ngx_http_error_505_page[] = +"" CRLF +"505 HTTP Version Not Supported" CRLF +"" CRLF +"

505 HTTP Version Not Supported

" CRLF +; + + static char ngx_http_error_507_page[] = "" CRLF "507 Insufficient Storage" CRLF @@ -395,7 +403,7 @@ static ngx_str_t ngx_http_error_pages[] = { ngx_string(ngx_http_error_502_page), ngx_string(ngx_http_error_503_page), ngx_string(ngx_http_error_504_page), - ngx_null_string, /* 505 */ + ngx_string(ngx_http_error_505_page), ngx_null_string, /* 506 */ ngx_string(ngx_http_error_507_page) diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index fcfa2ad..0fc5ab5 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -879,7 +879,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) case NGX_HTTP_CACHE_STALE: if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) - || c->stale_updating) && !r->cache_updater + || c->stale_updating) && !r->background && u->conf->cache_background_update) { r->cache->background = 1; @@ -892,7 +892,7 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) case NGX_HTTP_CACHE_UPDATING: if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING) - || c->stale_updating) && !r->cache_updater) + || c->stale_updating) && !r->background) { u->cache_status = rc; rc = NGX_OK; @@ -1076,14 +1076,14 @@ ngx_http_upstream_cache_background_update(ngx_http_request_t *r, } if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, - NGX_HTTP_SUBREQUEST_CLONE) + NGX_HTTP_SUBREQUEST_CLONE + |NGX_HTTP_SUBREQUEST_BACKGROUND) != NGX_OK) { return NGX_ERROR; } sr->header_only = 1; - sr->cache_updater = 1; return NGX_OK; } @@ -1606,7 +1606,6 @@ static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c) { - int tcp_nodelay; ngx_int_t rc; ngx_http_core_loc_conf_t *clcf; @@ -1646,22 +1645,10 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, + if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + return; } } @@ -2014,7 +2001,6 @@ static ngx_int_t ngx_http_upstream_send_request_body(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t do_write) { - int tcp_nodelay; ngx_int_t rc; ngx_chain_t *out, *cl, *ln; ngx_connection_t *c; @@ -2051,20 +2037,8 @@ ngx_http_upstream_send_request_body(ngx_http_request_t *r, c = u->peer.connection; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - return NGX_ERROR; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + return NGX_ERROR; } r->read_event_handler = ngx_http_upstream_read_request_handler; @@ -2822,7 +2796,6 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) { - int tcp_nodelay; ssize_t n; ngx_int_t rc; ngx_event_pipe_t *p; @@ -2903,21 +2876,9 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } - if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - return; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + if (clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; } n = u->buffer.last - u->buffer.pos; @@ -3176,7 +3137,6 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) static void ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) { - int tcp_nodelay; ngx_connection_t *c; ngx_http_core_loc_conf_t *clcf; @@ -3194,37 +3154,15 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) r->write_event_handler = ngx_http_upstream_upgraded_write_downstream; if (clcf->tcp_nodelay) { - tcp_nodelay = 1; - if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - return; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + if (ngx_tcp_nodelay(c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; } - if (u->peer.connection->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, u->peer.connection->log, 0, - "tcp_nodelay"); - - if (setsockopt(u->peer.connection->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(u->peer.connection, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_http_upstream_finalize_request(r, u, NGX_ERROR); - return; - } - - u->peer.connection->tcp_nodelay = NGX_TCP_NODELAY_SET; + if (ngx_tcp_nodelay(u->peer.connection) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; } } diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 1a9e521..ed78638 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -529,29 +529,8 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c) tcp_nodelay = 1; } - if (tcp_nodelay - && clcf->tcp_nodelay - && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) - { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) - == -1) - { -#if (NGX_SOLARIS) - /* Solaris returns EINVAL if a socket has been shut down */ - c->log_error = NGX_ERROR_IGNORE_EINVAL; -#endif - - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - - c->log_error = NGX_ERROR_INFO; - goto error; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + if (tcp_nodelay && clcf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + goto error; } for ( /* void */ ; out; out = fn) { diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index dac5046..7276531 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -619,6 +619,8 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) ngx_http_v2_queue_blocked_frame(r->stream->connection, frame); + r->stream->queued = 1; + cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { return NGX_ERROR; @@ -627,8 +629,6 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) cln->handler = ngx_http_v2_filter_cleanup; cln->data = r->stream; - r->stream->queued = 1; - fc->send_chain = ngx_http_v2_send_chain; fc->need_last_buf = 1; diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 9d4ef56..f6b26ed 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -222,7 +222,7 @@ ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) ngx_mail_session_t *s; ngx_mail_core_srv_conf_t *cscf; - if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { + if (ngx_ssl_create_connection(ssl, c, 0) != NGX_OK) { ngx_mail_close_connection(c); return; } diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c index dd50b5c..993c032 100644 --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -413,6 +413,7 @@ ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext) break; } ngx_debug_quit = 1; + /* fall through */ case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): ngx_quit = 1; action = ", shutting down"; diff --git a/src/stream/ngx_stream_access_module.c b/src/stream/ngx_stream_access_module.c index 1745cdf..a3020d4 100644 --- a/src/stream/ngx_stream_access_module.c +++ b/src/stream/ngx_stream_access_module.c @@ -299,28 +299,22 @@ ngx_stream_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_stream_access_rule_un_t *rule_un; #endif + all = 0; ngx_memzero(&cidr, sizeof(ngx_cidr_t)); value = cf->args->elts; - all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); - - if (!all) { + if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { + all = 1; #if (NGX_HAVE_UNIX_DOMAIN) - - if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { - cidr.family = AF_UNIX; - rc = NGX_OK; - - } else { - rc = ngx_ptocidr(&value[1], &cidr); - } - -#else - rc = ngx_ptocidr(&value[1], &cidr); + } else if (value[1].len == 5 && ngx_strcmp(value[1].data, "unix:") == 0) { + cidr.family = AF_UNIX; #endif + } else { + rc = ngx_ptocidr(&value[1], &cidr); + if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[1]); diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index db8c2a3..272708d 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -309,7 +309,6 @@ ngx_int_t ngx_stream_core_content_phase(ngx_stream_session_t *s, ngx_stream_phase_handler_t *ph) { - int tcp_nodelay; ngx_connection_t *c; ngx_stream_core_srv_conf_t *cscf; @@ -321,22 +320,10 @@ ngx_stream_core_content_phase(ngx_stream_session_t *s, if (c->type == SOCK_STREAM && cscf->tcp_nodelay - && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + && ngx_tcp_nodelay(c) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(c, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - c->tcp_nodelay = NGX_TCP_NODELAY_SET; + ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return NGX_OK; } cscf->handler(s); diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index fe52cb6..0afde1c 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -729,7 +729,6 @@ ngx_stream_proxy_connect(ngx_stream_session_t *s) static void ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) { - int tcp_nodelay; u_char *p; ngx_chain_t *cl; ngx_connection_t *c, *pc; @@ -745,22 +744,10 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s) if (pc->type == SOCK_STREAM && cscf->tcp_nodelay - && pc->tcp_nodelay == NGX_TCP_NODELAY_UNSET) + && ngx_tcp_nodelay(pc) != NGX_OK) { - ngx_log_debug0(NGX_LOG_DEBUG_STREAM, pc->log, 0, "tcp_nodelay"); - - tcp_nodelay = 1; - - if (setsockopt(pc->fd, IPPROTO_TCP, TCP_NODELAY, - (const void *) &tcp_nodelay, sizeof(int)) == -1) - { - ngx_connection_error(pc, ngx_socket_errno, - "setsockopt(TCP_NODELAY) failed"); - ngx_stream_proxy_next_upstream(s); - return; - } - - pc->tcp_nodelay = NGX_TCP_NODELAY_SET; + ngx_stream_proxy_next_upstream(s); + return; } pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c index 0740431..1266605 100644 --- a/src/stream/ngx_stream_realip_module.c +++ b/src/stream/ngx_stream_realip_module.c @@ -178,9 +178,15 @@ ngx_stream_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_stream_realip_srv_conf_t *rscf = conf; - ngx_int_t rc; - ngx_str_t *value; - ngx_cidr_t *cidr; + ngx_int_t rc; + ngx_str_t *value; + ngx_url_t u; + ngx_cidr_t c, *cidr; + ngx_uint_t i; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif value = cf->args->elts; @@ -192,31 +198,78 @@ ngx_stream_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } } - cidr = ngx_array_push(rscf->from); - if (cidr == NULL) { - return NGX_CONF_ERROR; - } - #if (NGX_HAVE_UNIX_DOMAIN) if (ngx_strcmp(value[1].data, "unix:") == 0) { + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + cidr->family = AF_UNIX; return NGX_CONF_OK; } #endif - rc = ngx_ptocidr(&value[1], cidr); + rc = ngx_ptocidr(&value[1], &c); + + if (rc != NGX_ERROR) { + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", + &value[1]); + } + + cidr = ngx_array_push(rscf->from); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + *cidr = c; + + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + u.host = value[1]; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in set_real_ip_from \"%V\"", + u.err, &u.host); + } - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", - &value[1]); 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[1]); + cidr = ngx_array_push_n(rscf->from, u.naddrs); + if (cidr == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(cidr, u.naddrs * sizeof(ngx_cidr_t)); + + for (i = 0; i < u.naddrs; i++) { + cidr[i].family = u.addrs[i].sockaddr->sa_family; + + switch (cidr[i].family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) u.addrs[i].sockaddr; + cidr[i].u.in6.addr = sin6->sin6_addr; + ngx_memset(cidr[i].u.in6.mask.s6_addr, 0xff, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) u.addrs[i].sockaddr; + cidr[i].u.in.addr = sin->sin_addr.s_addr; + cidr[i].u.in.mask = 0xffffffff; + break; + } } return NGX_CONF_OK; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 593776b..da26a41 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -352,13 +352,20 @@ ngx_stream_ssl_handler(ngx_stream_session_t *s) static ngx_int_t 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_int_t rc; + ngx_stream_session_t *s; + ngx_stream_ssl_conf_t *sslcf; + ngx_stream_core_srv_conf_t *cscf; s = c->data; - if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { + cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module); + + if (cscf->tcp_nodelay && ngx_tcp_nodelay(c) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_ssl_create_connection(ssl, c, 0) != NGX_OK) { return NGX_ERROR; } From 05b6bb9e3bec4615a5a7cc318f44b93a50f9b7ad Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 31 May 2017 11:42:21 +0300 Subject: [PATCH 003/414] Release 1.13.1-1 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index a36a3df..e0009f0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.13.1-1) experimental; urgency=medium + + * New upstream version 1.13.1. + + -- Christos Trochalakis Wed, 31 May 2017 11:41:59 +0300 + nginx (1.13.0-1) experimental; urgency=medium * New upstream release. From 1084313b41da6502ecb6b9a9cd97452d5aa8d025 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 20 Jun 2017 14:17:25 +0300 Subject: [PATCH 004/414] Release 1.13.1-2 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index e0009f0..fac5d1c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.13.1-2) unstable; urgency=medium + + * Upload to unstable. + + -- Christos Trochalakis Tue, 20 Jun 2017 14:16:52 +0300 + nginx (1.13.1-1) experimental; urgency=medium * New upstream version 1.13.1. From 5dcee0ba0ad487f103e55e35d526fe6e2e06f25a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 28 Jun 2017 11:05:50 +0300 Subject: [PATCH 005/414] New upstream version 1.13.2 --- CHANGES | 21 +++ CHANGES.ru | 22 +++ auto/cc/bcc | 1 - auto/cc/msvc | 1 - auto/cc/owc | 1 - auto/os/conf | 8 + auto/os/win32 | 1 + auto/unix | 5 +- configure | 2 +- src/core/nginx.h | 4 +- src/core/ngx_cycle.c | 4 +- src/core/ngx_file.c | 4 +- src/core/ngx_resolver.c | 9 +- src/core/ngx_resolver.h | 3 +- src/core/ngx_rwlock.c | 11 +- src/core/ngx_rwlock.h | 1 + .../modules/ngx_http_chunked_filter_module.c | 158 ++++++++++++---- .../modules/ngx_http_gzip_filter_module.c | 8 +- .../modules/ngx_http_headers_filter_module.c | 170 +++++++++++++++--- .../modules/ngx_http_range_filter_module.c | 3 + src/http/modules/ngx_http_ssi_filter_module.c | 2 +- .../modules/ngx_http_userid_filter_module.c | 4 + src/http/ngx_http_core_module.c | 8 + src/http/ngx_http_request.c | 8 + src/http/ngx_http_request.h | 2 + src/http/ngx_http_upstream.c | 47 +++-- src/http/ngx_http_variables.c | 15 ++ src/http/v2/ngx_http_v2.c | 122 +++++++------ src/http/v2/ngx_http_v2.h | 9 + src/http/v2/ngx_http_v2_filter_module.c | 166 +++++++++++++++-- src/os/unix/ngx_udp_sendmsg_chain.c | 6 +- 31 files changed, 666 insertions(+), 160 deletions(-) diff --git a/CHANGES b/CHANGES index 992cc70..e7126ff 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,25 @@ +Changes with nginx 1.13.2 27 Jun 2017 + + *) Change: nginx now returns 200 instead of 416 when a range starting + with 0 is requested from an empty file. + + *) Feature: the "add_trailer" directive. + Thanks to Piotr Sikora. + + *) Bugfix: nginx could not be built on Cygwin and NetBSD; the bug had + appeared in 1.13.0. + + *) Bugfix: nginx could not be built under MSYS2 / MinGW 64-bit. + Thanks to Orgad Shaneh. + + *) Bugfix: a segmentation fault might occur in a worker process when + using SSI with many includes and proxy_pass with variables. + + *) Bugfix: in the ngx_http_v2_module. + Thanks to Piotr Sikora. + + Changes with nginx 1.13.1 30 May 2017 *) Feature: now a hostname can be used as the "set_real_ip_from" diff --git a/CHANGES.ru b/CHANGES.ru index d42b90f..69e2be1 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,26 @@ +Изменения в nginx 1.13.2 27.06.2017 + + *) Изменение: теперь при запросе диапазона, начинающегося с 0, из + пустого файла nginx возвращает ответ 200 вместо 416. + + *) Добавление: директива add_trailer. + Спасибо Piotr Sikora. + + *) Исправление: nginx не собирался под Cygwin и NetBSD; ошибка появилась + в 1.13.0. + + *) Исправление: nginx не собирался под MSYS2 / MinGW 64-bit. + Спасибо Orgad Shaneh. + + *) Исправление: при использовании SSI с большим количеством подзапросов + и proxy_pass с переменными в рабочем процессе мог произойти + segmentation fault. + + *) Исправление: в модуле ngx_http_v2_module. + Спасибо Piotr Sikora. + + Изменения в nginx 1.13.1 30.05.2017 *) Добавление: теперь в качестве параметра директивы set_real_ip_from diff --git a/auto/cc/bcc b/auto/cc/bcc index ec82e60..e990a9f 100644 --- a/auto/cc/bcc +++ b/auto/cc/bcc @@ -62,7 +62,6 @@ ngx_include_opt="-I" ngx_objout="-o" ngx_binout="-e" ngx_objext="obj" -ngx_binext=".exe" ngx_long_start='@&&| ' diff --git a/auto/cc/msvc b/auto/cc/msvc index 4eef101..8257252 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -142,7 +142,6 @@ ngx_pic_opt= ngx_objout="-Fo" ngx_binout="-Fe" ngx_objext="obj" -ngx_binext=".exe" ngx_long_start='@<< ' diff --git a/auto/cc/owc b/auto/cc/owc index a063aa3..f7fd88c 100644 --- a/auto/cc/owc +++ b/auto/cc/owc @@ -84,7 +84,6 @@ ngx_include_opt="-i=" ngx_objout="-fo" ngx_binout="-fe=" ngx_objext="obj" -ngx_binext=".exe" ngx_regex_dirsep='\\' ngx_dirsep="\\" diff --git a/auto/os/conf b/auto/os/conf index 6ad0e74..6096af5 100644 --- a/auto/os/conf +++ b/auto/os/conf @@ -41,6 +41,14 @@ case "$NGX_PLATFORM" in ' ;; + NetBSD:*) + CORE_INCS="$UNIX_INCS" + CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" + CORE_SRCS="$UNIX_SRCS" + + NGX_RPATH=YES + ;; + HP-UX:*) # HP/UX have=NGX_HPUX . auto/have_headers diff --git a/auto/os/win32 b/auto/os/win32 index 650cf49..7a82774 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -13,6 +13,7 @@ NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS ngx_pic_opt= +ngx_binext=".exe" case "$NGX_CC_NAME" in diff --git a/auto/unix b/auto/unix index 7c6a855..10835f6 100644 --- a/auto/unix +++ b/auto/unix @@ -428,7 +428,10 @@ ngx_feature_incs="#include #include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_PKTINFO, NULL, 0)" +ngx_feature_test="struct in_pktinfo pkt; + pkt.ipi_spec_dst.s_addr = INADDR_ANY; + (void) pkt; + setsockopt(0, IPPROTO_IP, IP_PKTINFO, NULL, 0)" . auto/feature diff --git a/configure b/configure index ceff15e..7e6e33a 100755 --- a/configure +++ b/configure @@ -36,7 +36,7 @@ if test -z "$NGX_PLATFORM"; then NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE"; case "$NGX_SYSTEM" in - MINGW32_*) + MINGW32_* | MINGW64_* | MSYS_*) NGX_PLATFORM=win32 ;; esac diff --git a/src/core/nginx.h b/src/core/nginx.h index 8cc2d80..37e257f 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013001 -#define NGINX_VERSION "1.13.1" +#define nginx_version 1013002 +#define NGINX_VERSION "1.13.2" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index aee7a58..675a506 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -1124,9 +1124,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) { ngx_file_info_t fi; - if (ngx_file_info((const char *) file[i].name.data, &fi) - == NGX_FILE_ERROR) - { + if (ngx_file_info(file[i].name.data, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed", file[i].name.data); diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index b7dd4bc..3a94089 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -622,9 +622,7 @@ ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user) { ngx_file_info_t fi; - if (ngx_file_info((const char *) path[i]->name.data, &fi) - == NGX_FILE_ERROR) - { + if (ngx_file_info(path[i]->name.data, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed", path[i]->name.data); return NGX_ERROR; diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index e140ab6..91f8a5e 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -443,7 +443,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) name.data = ngx_resolver_alloc(r, name.len); if (name.data == NULL) { - return NGX_ERROR; + goto failed; } if (slen == ctx->service.len) { @@ -481,6 +481,8 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) ngx_resolver_free(r, ctx->event); } +failed: + ngx_resolver_free(r, ctx); return NGX_ERROR; @@ -744,6 +746,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, last->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->async = 1; do { ctx->node = rn; @@ -890,6 +893,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->async = 1; do { ctx->node = rn; @@ -1021,6 +1025,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) ctx->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->async = 1; ctx->node = rn; /* unlock addr mutex */ @@ -1117,6 +1122,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) /* unlock addr mutex */ ctx->state = NGX_AGAIN; + ctx->async = 1; ctx->node = rn; return NGX_OK; @@ -3017,6 +3023,7 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) srv = cctx->srvs; ctx->count--; + ctx->async |= cctx->async; srv->ctx = NULL; srv->state = cctx->state; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index a0d6fc3..6f099b7 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -218,7 +218,8 @@ struct ngx_resolver_ctx_s { void *data; ngx_msec_t timeout; - ngx_uint_t quick; /* unsigned quick:1; */ + unsigned quick:1; + unsigned async:1; ngx_uint_t recursion; ngx_event_t *event; }; diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index 905de78..ed2b0f8 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -94,7 +94,7 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) readers = *lock; if (readers == NGX_RWLOCK_WLOCK) { - *lock = 0; + (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); return; } @@ -109,6 +109,15 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) } +void +ngx_rwlock_downgrade(ngx_atomic_t *lock) +{ + if (*lock == NGX_RWLOCK_WLOCK) { + *lock = 1; + } +} + + #else #if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE) diff --git a/src/core/ngx_rwlock.h b/src/core/ngx_rwlock.h index 8b16eca..41b42aa 100644 --- a/src/core/ngx_rwlock.h +++ b/src/core/ngx_rwlock.h @@ -16,6 +16,7 @@ void ngx_rwlock_wlock(ngx_atomic_t *lock); void ngx_rwlock_rlock(ngx_atomic_t *lock); void ngx_rwlock_unlock(ngx_atomic_t *lock); +void ngx_rwlock_downgrade(ngx_atomic_t *lock); #endif /* _NGX_RWLOCK_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c index ac2e3e8..4d6fd3e 100644 --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -17,6 +17,8 @@ typedef struct { static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf); +static ngx_chain_t *ngx_http_chunked_create_trailers(ngx_http_request_t *r, + ngx_http_chunked_filter_ctx_t *ctx); static ngx_http_module_t ngx_http_chunked_filter_module_ctx = { @@ -69,27 +71,29 @@ ngx_http_chunked_header_filter(ngx_http_request_t *r) return ngx_http_next_header_filter(r); } - if (r->headers_out.content_length_n == -1) { - if (r->http_version < NGX_HTTP_VERSION_11) { - r->keepalive = 0; + if (r->headers_out.content_length_n == -1 + || r->expect_trailers) + { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - } else { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->chunked_transfer_encoding) { - r->chunked = 1; - - ctx = ngx_pcalloc(r->pool, - sizeof(ngx_http_chunked_filter_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); - - } else { - r->keepalive = 0; + if (r->http_version >= NGX_HTTP_VERSION_11 + && clcf->chunked_transfer_encoding) + { + if (r->expect_trailers) { + ngx_http_clear_content_length(r); } + + r->chunked = 1; + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); + + } else if (r->headers_out.content_length_n == -1) { + r->keepalive = 0; } } @@ -179,26 +183,17 @@ ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (cl->buf->last_buf) { - tl = ngx_chain_get_free_buf(r->pool, &ctx->free); + tl = ngx_http_chunked_create_trailers(r, ctx); if (tl == NULL) { return NGX_ERROR; } - b = tl->buf; - - b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; - b->temporary = 0; - b->memory = 1; - b->last_buf = 1; - b->pos = (u_char *) CRLF "0" CRLF CRLF; - b->last = b->pos + 7; - cl->buf->last_buf = 0; *ll = tl; if (size == 0) { - b->pos += 2; + tl->buf->pos += 2; } } else if (size > 0) { @@ -230,6 +225,109 @@ ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } +static ngx_chain_t * +ngx_http_chunked_create_trailers(ngx_http_request_t *r, + ngx_http_chunked_filter_ctx_t *ctx) +{ + size_t len; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t *cl; + ngx_list_part_t *part; + ngx_table_elt_t *header; + + 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 += header[i].key.len + sizeof(": ") - 1 + + header[i].value.len + sizeof(CRLF) - 1; + } + + 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_chunked_filter_module; + b->temporary = 0; + b->memory = 1; + b->last_buf = 1; + + if (len == 0) { + b->pos = (u_char *) CRLF "0" CRLF CRLF; + b->last = b->pos + sizeof(CRLF "0" CRLF CRLF) - 1; + return cl; + } + + len += sizeof(CRLF "0" CRLF CRLF) - 1; + + b->pos = ngx_palloc(r->pool, len); + if (b->pos == NULL) { + return NULL; + } + + b->last = b->pos; + + *b->last++ = CR; *b->last++ = LF; + *b->last++ = '0'; + *b->last++ = CR; *b->last++ = LF; + + 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, + "http trailer: \"%V: %V\"", + &header[i].key, &header[i].value); + + b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); + *b->last++ = ':'; *b->last++ = ' '; + + b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); + *b->last++ = CR; *b->last++ = LF; + } + + *b->last++ = CR; *b->last++ = LF; + + return cl; +} + + static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index 287fd36..73b6d89 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -1084,10 +1084,6 @@ ngx_http_gzip_ratio_variable(ngx_http_request_t *r, ngx_uint_t zint, zfrac; ngx_http_gzip_ctx_t *ctx; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); if (ctx == NULL || ctx->zout == 0) { @@ -1095,6 +1091,10 @@ ngx_http_gzip_ratio_variable(ngx_http_request_t *r, return NGX_OK; } + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3); if (v->data == NULL) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index 94dc51e..e5f1eb5 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -48,6 +48,7 @@ typedef struct { time_t expires_time; ngx_http_complex_value_t *expires_value; ngx_array_t *headers; + ngx_array_t *trailers; } ngx_http_headers_conf_t; @@ -98,15 +99,23 @@ static ngx_command_t ngx_http_headers_filter_commands[] = { ngx_http_headers_expires, NGX_HTTP_LOC_CONF_OFFSET, 0, - NULL}, + NULL }, { ngx_string("add_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE23, ngx_http_headers_add, NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, + offsetof(ngx_http_headers_conf_t, headers), + NULL }, + + { ngx_string("add_trailer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_headers_add, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_headers_conf_t, trailers), + NULL }, ngx_null_command }; @@ -144,6 +153,7 @@ ngx_module_t ngx_http_headers_filter_module = { static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t @@ -154,10 +164,15 @@ ngx_http_headers_filter(ngx_http_request_t *r) ngx_http_header_val_t *h; ngx_http_headers_conf_t *conf; + if (r != r->main) { + return ngx_http_next_header_filter(r); + } + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); - if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL) - || r != r->main) + if (conf->expires == NGX_HTTP_EXPIRES_OFF + && conf->headers == NULL + && conf->trailers == NULL) { return ngx_http_next_header_filter(r); } @@ -206,10 +221,100 @@ ngx_http_headers_filter(ngx_http_request_t *r) } } + if (conf->trailers) { + h = conf->trailers->elts; + for (i = 0; i < conf->trailers->nelts; i++) { + + if (!safe_status && !h[i].always) { + continue; + } + + r->expect_trailers = 1; + break; + } + } + return ngx_http_next_header_filter(r); } +static ngx_int_t +ngx_http_trailers_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_str_t value; + ngx_uint_t i, safe_status; + ngx_chain_t *cl; + ngx_table_elt_t *t; + ngx_http_header_val_t *h; + ngx_http_headers_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); + + if (in == NULL + || conf->trailers == NULL + || !r->expect_trailers + || r->header_only) + { + return ngx_http_next_body_filter(r, in); + } + + for (cl = in; cl; cl = cl->next) { + if (cl->buf->last_buf) { + break; + } + } + + if (cl == NULL) { + return ngx_http_next_body_filter(r, in); + } + + switch (r->headers_out.status) { + + case NGX_HTTP_OK: + case NGX_HTTP_CREATED: + case NGX_HTTP_NO_CONTENT: + case NGX_HTTP_PARTIAL_CONTENT: + case NGX_HTTP_MOVED_PERMANENTLY: + case NGX_HTTP_MOVED_TEMPORARILY: + case NGX_HTTP_SEE_OTHER: + case NGX_HTTP_NOT_MODIFIED: + case NGX_HTTP_TEMPORARY_REDIRECT: + case NGX_HTTP_PERMANENT_REDIRECT: + safe_status = 1; + break; + + default: + safe_status = 0; + break; + } + + h = conf->trailers->elts; + for (i = 0; i < conf->trailers->nelts; i++) { + + if (!safe_status && !h[i].always) { + continue; + } + + if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { + return NGX_ERROR; + } + + if (value.len) { + t = ngx_list_push(&r->headers_out.trailers); + if (t == NULL) { + return NGX_ERROR; + } + + t->key = h[i].key; + t->value = value; + t->hash = 1; + } + } + + return ngx_http_next_body_filter(r, in); +} + + static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) { @@ -557,6 +662,7 @@ ngx_http_headers_create_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * conf->headers = NULL; + * conf->trailers = NULL; * conf->expires_time = 0; * conf->expires_value = NULL; */ @@ -587,6 +693,10 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->headers = prev->headers; } + if (conf->trailers == NULL) { + conf->trailers = prev->trailers; + } + return NGX_CONF_OK; } @@ -597,6 +707,9 @@ ngx_http_headers_filter_init(ngx_conf_t *cf) ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_headers_filter; + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_trailers_filter; + return NGX_OK; } @@ -674,42 +787,49 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_headers_conf_t *hcf = conf; - ngx_str_t *value; - ngx_uint_t i; - ngx_http_header_val_t *hv; - ngx_http_set_header_t *set; - ngx_http_compile_complex_value_t ccv; + ngx_str_t *value; + ngx_uint_t i; + ngx_array_t **headers; + ngx_http_header_val_t *hv; + ngx_http_set_header_t *set; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - if (hcf->headers == NULL) { - hcf->headers = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_header_val_t)); - if (hcf->headers == NULL) { + headers = (ngx_array_t **) ((char *) hcf + cmd->offset); + + if (*headers == NULL) { + *headers = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_header_val_t)); + if (*headers == NULL) { return NGX_CONF_ERROR; } } - hv = ngx_array_push(hcf->headers); + hv = ngx_array_push(*headers); if (hv == NULL) { return NGX_CONF_ERROR; } hv->key = value[1]; - hv->handler = ngx_http_add_header; + hv->handler = NULL; hv->offset = 0; hv->always = 0; - set = ngx_http_set_headers; - for (i = 0; set[i].name.len; i++) { - if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) { - continue; + if (headers == &hcf->headers) { + hv->handler = ngx_http_add_header; + + set = ngx_http_set_headers; + for (i = 0; set[i].name.len; i++) { + if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) { + continue; + } + + hv->offset = set[i].offset; + hv->handler = set[i].handler; + + break; } - - hv->offset = set[i].offset; - hv->handler = set[i].handler; - - break; } if (value[2].len == 0) { diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 8ffca82..7ad9db9 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -382,6 +382,9 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, if (ranges-- == 0) { return NGX_DECLINED; } + + } else if (start == 0) { + return NGX_DECLINED; } if (*p++ != ',') { diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index 6fb1fbe..b92ad4c 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -2388,7 +2388,7 @@ ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ctx->timefmt.len = value->len; ctx->timefmt.data = ngx_pnalloc(r->pool, value->len + 1); if (ctx->timefmt.data == NULL) { - return NGX_HTTP_SSI_ERROR; + return NGX_ERROR; } ngx_cpystrn(ctx->timefmt.data, value->data, value->len + 1); diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index 0dbacba..a1a5493 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -472,6 +472,10 @@ ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, vv = ngx_http_get_indexed_variable(r, ngx_http_userid_reset_index); + if (vv == NULL || vv->not_found) { + return NGX_ERROR; + } + if (vv->len == 0 || (vv->len == 1 && vv->data[0] == '0')) { if (conf->mark == '\0' diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 7e40e78..02059ef 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1353,6 +1353,7 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r, r->uri.len = alias + path.len; r->uri.data = ngx_pnalloc(r->pool, r->uri.len); if (r->uri.data == NULL) { + r->uri.len = 0; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return NGX_OK; } @@ -2484,6 +2485,13 @@ ngx_http_subrequest(ngx_http_request_t *r, return NGX_ERROR; } + if (ngx_list_init(&sr->headers_out.trailers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); sr->main_conf = cscf->ctx->main_conf; sr->srv_conf = cscf->ctx->srv_conf; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index cc3722f..de1b202 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -562,6 +562,14 @@ ngx_http_create_request(ngx_connection_t *c) return NULL; } + if (ngx_list_init(&r->headers_out.trailers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_destroy_pool(r->pool); + return NULL; + } + r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { ngx_destroy_pool(r->pool); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 283c582..f7f3e97 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -252,6 +252,7 @@ typedef struct { typedef struct { ngx_list_t headers; + ngx_list_t trailers; ngx_uint_t status; ngx_str_t status_line; @@ -514,6 +515,7 @@ struct ngx_http_request_s { unsigned pipeline:1; unsigned chunked:1; unsigned header_only:1; + unsigned expect_trailers:1; unsigned keepalive:1; unsigned lingering_close:1; unsigned discard_body:1; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 0fc5ab5..c394b29 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -182,7 +182,9 @@ static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); #if (NGX_HTTP_SSL) static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); -static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c); +static void ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c); +static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, + ngx_http_upstream_t *u, ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -1143,11 +1145,14 @@ ngx_http_upstream_cache_check_range(ngx_http_request_t *r, static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) { + ngx_uint_t run_posted; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_http_upstream_resolved_t *ur; + run_posted = ctx->async; + r = ctx->data; c = r->connection; @@ -1211,7 +1216,9 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) failed: - ngx_http_run_posted_requests(c); + if (run_posted) { + ngx_http_run_posted_requests(c); + } } @@ -1662,26 +1669,43 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, ngx_add_timer(c->write, u->conf->connect_timeout); } - c->ssl->handler = ngx_http_upstream_ssl_handshake; + c->ssl->handler = ngx_http_upstream_ssl_handshake_handler; return; } - ngx_http_upstream_ssl_handshake(c); + ngx_http_upstream_ssl_handshake(r, u, c); } static void -ngx_http_upstream_ssl_handshake(ngx_connection_t *c) +ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c) { - long rc; ngx_http_request_t *r; ngx_http_upstream_t *u; r = c->data; + u = r->upstream; + c = r->connection; ngx_http_set_log_request(c->log, r); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl handshake: \"%V?%V\"", + &r->uri, &r->args); + + ngx_http_upstream_ssl_handshake(r, u, u->peer.connection); + + ngx_http_run_posted_requests(c); +} + + +static void +ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_connection_t *c) +{ + long rc; + if (c->ssl->handshaked) { if (u->conf->ssl_verify) { @@ -1709,28 +1733,19 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; - c = r->connection; - ngx_http_upstream_send_request(r, u, 1); - ngx_http_run_posted_requests(c); return; } if (c->write->timedout) { - c = r->connection; ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); - ngx_http_run_posted_requests(c); return; } failed: - c = r->connection; - ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); - - ngx_http_run_posted_requests(c); } @@ -2729,7 +2744,7 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, rev = c->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http upstream process body on memory"); + "http upstream process body in memory"); if (rev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 6138819..cfb538a 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -38,6 +38,8 @@ static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r, @@ -365,6 +367,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("sent_http_"), NULL, ngx_http_variable_unknown_header_out, 0, NGX_HTTP_VAR_PREFIX, 0 }, + { ngx_string("sent_trailer_"), NULL, ngx_http_variable_unknown_trailer_out, + 0, NGX_HTTP_VAR_PREFIX, 0 }, + { ngx_string("cookie_"), NULL, ngx_http_variable_cookie, 0, NGX_HTTP_VAR_PREFIX, 0 }, @@ -934,6 +939,16 @@ ngx_http_variable_unknown_header_out(ngx_http_request_t *r, } +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, + &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_list_part_t *part, size_t prefix) diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index ed78638..7725616 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -28,6 +28,7 @@ #define NGX_HTTP_V2_HTTP_1_1_REQUIRED 0xd /* frame sizes */ +#define NGX_HTTP_V2_SETTINGS_ACK_SIZE 0 #define NGX_HTTP_V2_RST_STREAM_SIZE 4 #define NGX_HTTP_V2_PRIORITY_SIZE 5 #define NGX_HTTP_V2_PING_SIZE 8 @@ -128,8 +129,7 @@ static ngx_http_v2_node_t *ngx_http_v2_get_closed_node( #define ngx_http_v2_index_size(h2scf) (h2scf->streams_index_mask + 1) #define ngx_http_v2_index(h2scf, sid) ((sid >> 1) & h2scf->streams_index_mask) -static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, - ngx_uint_t ack); +static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c); static ngx_int_t ngx_http_v2_settings_frame_handler( ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, @@ -269,7 +269,7 @@ ngx_http_v2_init(ngx_event_t *rev) return; } - if (ngx_http_v2_send_settings(h2c, 0) == NGX_ERROR) { + if (ngx_http_v2_send_settings(h2c) == NGX_ERROR) { ngx_http_close_connection(c); return; } @@ -1568,6 +1568,10 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, rc = ngx_http_v2_pseudo_header(r, header); if (rc == NGX_OK) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 pseudo-header: \":%V: %V\"", + &header->name, &header->value); + return ngx_http_v2_state_header_complete(h2c, pos, end); } @@ -1609,36 +1613,40 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_INTERNAL_ERROR); } - return ngx_http_v2_state_header_complete(h2c, pos, end); - } + } else { + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } - h = ngx_list_push(&r->headers_in.headers); - if (h == NULL) { - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); - } + h->key.len = header->name.len; + h->key.data = header->name.data; - h->key.len = header->name.len; - h->key.data = header->name.data; + /* + * TODO Optimization: precalculate hash + * and handler for indexed headers. + */ + h->hash = ngx_hash_key(h->key.data, h->key.len); - /* TODO Optimization: precalculate hash and handler for indexed headers. */ - h->hash = ngx_hash_key(h->key.data, h->key.len); + h->value.len = header->value.len; + h->value.data = header->value.data; - h->value.len = header->value.len; - h->value.data = header->value.data; + h->lowcase_key = h->key.data; - h->lowcase_key = h->key.data; + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - 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); - 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) { - goto error; + if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { + goto error; + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 http header: \"%V: %V\"", &h->key, &h->value); + "http2 http header: \"%V: %V\"", + &header->name, &header->value); return ngx_http_v2_state_header_complete(h2c, pos, end); @@ -1951,8 +1959,6 @@ ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); } - ngx_http_v2_send_settings(h2c, 1); - return ngx_http_v2_state_settings_params(h2c, pos, end); } @@ -1961,7 +1967,11 @@ static u_char * ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - ngx_uint_t id, value; + ssize_t window_delta; + ngx_uint_t id, value; + ngx_http_v2_out_frame_t *frame; + + window_delta = 0; while (h2c->state.length) { if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) { @@ -1987,12 +1997,7 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_FLOW_CTRL_ERROR); } - if (ngx_http_v2_adjust_windows(h2c, value - h2c->init_window) - != NGX_OK) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } + window_delta = value - h2c->init_window; h2c->init_window = value; break; @@ -2020,6 +2025,22 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE; } + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_SETTINGS_ACK_SIZE, + NGX_HTTP_V2_SETTINGS_FRAME, + NGX_HTTP_V2_ACK_FLAG, 0); + if (frame == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + ngx_http_v2_queue_ordered_frame(h2c, frame); + + if (window_delta) { + if (ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + } + return ngx_http_v2_state_complete(h2c, pos, end); } @@ -2463,7 +2484,7 @@ ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, static ngx_int_t -ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) +ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c) { size_t len; ngx_buf_t *buf; @@ -2471,8 +2492,8 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_out_frame_t *frame; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 send SETTINGS frame ack:%ui", ack); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send SETTINGS frame"); frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t)); if (frame == NULL) { @@ -2484,7 +2505,7 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) return NGX_ERROR; } - len = ack ? 0 : (sizeof(uint16_t) + sizeof(uint32_t)) * 3; + len = NGX_HTTP_V2_SETTINGS_PARAM_SIZE * 3; buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len); if (buf == NULL) { @@ -2508,28 +2529,26 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) buf->last = ngx_http_v2_write_len_and_type(buf->last, len, NGX_HTTP_V2_SETTINGS_FRAME); - *buf->last++ = ack ? NGX_HTTP_V2_ACK_FLAG : NGX_HTTP_V2_NO_FLAG; + *buf->last++ = NGX_HTTP_V2_NO_FLAG; buf->last = ngx_http_v2_write_sid(buf->last, 0); - if (!ack) { - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); - buf->last = ngx_http_v2_write_uint16(buf->last, - NGX_HTTP_V2_MAX_STREAMS_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, - h2scf->concurrent_streams); + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_MAX_STREAMS_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + h2scf->concurrent_streams); - buf->last = ngx_http_v2_write_uint16(buf->last, + buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size); + buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size); - buf->last = ngx_http_v2_write_uint16(buf->last, - NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, - NGX_HTTP_V2_MAX_FRAME_SIZE); - } + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + NGX_HTTP_V2_MAX_FRAME_SIZE); ngx_http_v2_queue_blocked_frame(h2c, frame); @@ -3313,6 +3332,7 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) static const u_char ending[] = " HTTP/2.0"; if (r->method_name.len == 0 + || r->schema_start == NULL || r->unparsed_uri.len == 0) { ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index be34a09..4804658 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -261,6 +261,15 @@ ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t *h2c, } +static ngx_inline void +ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + frame->next = h2c->last_out; + h2c->last_out = frame; +} + + void ngx_http_v2_init(ngx_event_t *rev); void ngx_http_v2_request_headers_init(void); diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 7276531..8621e7a 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -50,13 +50,17 @@ #define NGX_HTTP_V2_SERVER_INDEX 54 #define NGX_HTTP_V2_VARY_INDEX 59 +#define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 + static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, ngx_uint_t lower); static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value); 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_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_trailers_frame( + ngx_http_request_t *r); static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit); @@ -612,7 +616,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) header[i].value.len, tmp); } - frame = ngx_http_v2_create_headers_frame(r, start, pos); + frame = ngx_http_v2_create_headers_frame(r, start, pos, r->header_only); if (frame == NULL) { return NGX_ERROR; } @@ -636,6 +640,118 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } +static ngx_http_v2_out_frame_t * +ngx_http_v2_create_trailers_frame(ngx_http_request_t *r) +{ + u_char *pos, *start, *tmp; + size_t len, tmp_len; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *header; + + len = 0; + tmp_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; + } + + if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "too long response trailer name: \"%V\"", + &header[i].key); + return NULL; + } + + if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "too long response trailer value: \"%V: %V\"", + &header[i].key, &header[i].value); + return NULL; + } + + len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len + + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; + + if (header[i].key.len > tmp_len) { + tmp_len = header[i].key.len; + } + + if (header[i].value.len > tmp_len) { + tmp_len = header[i].value.len; + } + } + + if (len == 0) { + return NGX_HTTP_V2_NO_TRAILERS; + } + + tmp = ngx_palloc(r->pool, tmp_len); + pos = ngx_pnalloc(r->pool, len); + + if (pos == NULL || tmp == NULL) { + return NULL; + } + + start = pos; + + 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; + } + +#if (NGX_DEBUG) + if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { + ngx_strlow(tmp, header[i].key.data, header[i].key.len); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 output trailer: \"%*s: %V\"", + header[i].key.len, tmp, &header[i].value); + } +#endif + + *pos++ = 0; + + pos = ngx_http_v2_write_name(pos, header[i].key.data, + header[i].key.len, tmp); + + pos = ngx_http_v2_write_value(pos, header[i].value.data, + header[i].value.len, tmp); + } + + return ngx_http_v2_create_headers_frame(r, start, pos, 1); +} + + static u_char * ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, ngx_uint_t lower) @@ -686,7 +802,7 @@ ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value) static ngx_http_v2_out_frame_t * ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, - u_char *end) + u_char *end, ngx_uint_t fin) { u_char type, flags; size_t rest, frame_size; @@ -707,12 +823,12 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, frame->stream = stream; frame->length = rest; frame->blocked = 1; - frame->fin = r->header_only; + frame->fin = fin; ll = &frame->first; type = NGX_HTTP_V2_HEADERS_FRAME; - flags = r->header_only ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; + flags = fin ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; frame_size = stream->connection->frame_size; for ( ;; ) { @@ -776,7 +892,7 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, continue; } - b->last_buf = r->header_only; + b->last_buf = fin; cl->next = NULL; frame->last = cl; @@ -798,7 +914,7 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) ngx_http_request_t *r; ngx_http_v2_stream_t *stream; ngx_http_v2_loc_conf_t *h2lcf; - ngx_http_v2_out_frame_t *frame; + ngx_http_v2_out_frame_t *frame, *trailers; ngx_http_v2_connection_t *h2c; r = fc->data; @@ -872,6 +988,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) frame_size = (h2lcf->chunk_size < h2c->frame_size) ? h2lcf->chunk_size : h2c->frame_size; + trailers = NGX_HTTP_V2_NO_TRAILERS; + #if (NGX_SUPPRESS_WARN) cl = NULL; #endif @@ -934,19 +1052,39 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) size -= rest; } - frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl); - if (frame == NULL) { - return NGX_CHAIN_ERROR; + if (cl->buf->last_buf) { + trailers = ngx_http_v2_create_trailers_frame(r); + if (trailers == NULL) { + return NGX_CHAIN_ERROR; + } + + if (trailers != NGX_HTTP_V2_NO_TRAILERS) { + cl->buf->last_buf = 0; + } } - ngx_http_v2_queue_frame(h2c, frame); + if (frame_size || cl->buf->last_buf) { + frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, + out, cl); + if (frame == NULL) { + return NGX_CHAIN_ERROR; + } - h2c->send_window -= frame_size; + ngx_http_v2_queue_frame(h2c, frame); - stream->send_window -= frame_size; - stream->queued++; + h2c->send_window -= frame_size; + + stream->send_window -= frame_size; + stream->queued++; + } if (in == NULL) { + + if (trailers != NGX_HTTP_V2_NO_TRAILERS) { + ngx_http_v2_queue_frame(h2c, trailers); + stream->queued++; + } + break; } diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c index 5f1cfa5..5399c79 100644 --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -206,13 +206,13 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) #if (NGX_HAVE_MSGHDR_MSG_CONTROL) #if (NGX_HAVE_IP_SENDSRCADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; + 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))]; + 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))]; + u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; #endif #endif From 57a32c6bb8dd5f197e9746c68aa9f059cbd86b59 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 28 Jun 2017 11:16:10 +0300 Subject: [PATCH 006/414] Merge ca translations Thanks: Alytidae Closes: #865996 --- debian/po/ca.po | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 debian/po/ca.po diff --git a/debian/po/ca.po b/debian/po/ca.po new file mode 100644 index 0000000..d9ce72d --- /dev/null +++ b/debian/po/ca.po @@ -0,0 +1,56 @@ +# Nginx debconf translations +# Copyright (C) 2016 Christos Trochalakis +# This file is distributed under the same license as the nginx package. +# Christos Trochalakis , 2016. +# Alytidae , 2017 +msgid "" +msgstr "" +"Project-Id-Version: nginx\n" +"Report-Msgid-Bugs-To: nginx@packages.debian.org\n" +"POT-Creation-Date: 2016-10-04 20:03+0300\n" +"PO-Revision-Date: 2017-06-19 20:26+0100\n" +"Last-Translator: Alytidae \n" +"Language-Team: catalan \n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "Possible insecure nginx log files" +msgstr "És possible que els fitxers de registre nginx siguin insegurs" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "" +"The following log files under /var/log/nginx directory are symlinks owned by " +"www-data:" +msgstr "" +"Els següents fitxers de registre, sota el directori /var/log/nginx, són " +"enllaços simbòlics propietat de 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 "" +"Des de la versió 1.4.4-4 de nginx, /var/log/nginx ha estat propietat de " +"www-data. A causa d'això, www-data podria tenir enllaços simbòlics d'arxius " +"de registre a ubicacions sensibles que, al seu torn, podrien donar lloc a " +"atacs d'escalada de privilegis. Encara que els permisos de /var/log/nginx " +"estan arreglats és possible que encara existeixin alguns enllaços simbòlics " +"insegurs. Per tant, assegura't de comprovar les ubicacions esmentades." From accf9ea73380a63d9be1dd70b6e51c33a1814aea Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 28 Jun 2017 11:18:04 +0300 Subject: [PATCH 007/414] Merge es translations Thanks: Jonathan Bustillos Closes: #855610 --- debian/po/es.po | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 debian/po/es.po diff --git a/debian/po/es.po b/debian/po/es.po new file mode 100644 index 0000000..552ab2f --- /dev/null +++ b/debian/po/es.po @@ -0,0 +1,78 @@ +# Nginx debconf translations +# Copyright (C) 2016 Christos Trochalakis +# This file is distributed under the same license as the nginx package. +# Christos Trochalakis , 2016. +# Changes: +# - Initial translation +# Jonathan Bustillos , 2017. +# +# Traductores, si no conocen el formato PO, merece la pena leer la +# documentación de gettext, especialmente las secciones dedicadas a este +# formato, por ejemplo ejecutando: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Equipo de traducción al español, por favor lean antes de traducir +# los siguientes documentos: +# +# - El proyecto de traducción de Debian al español +# http://www.debian.org/intl/spanish/ +# especialmente las notas y normas de traducción en +# http://www.debian.org/intl/spanish/notas +# +# - La guía de traducción de po's de debconf: +# /usr/share/doc/po-debconf/README-trans +# o http://www.debian.org/intl/l10n/po-debconf/README-trans +msgid "" +msgstr "" +"Project-Id-Version: nginx\n" +"Report-Msgid-Bugs-To: nginx@packages.debian.org\n" +"POT-Creation-Date: 2016-10-04 20:03+0300\n" +"PO-Revision-Date: 2017-02-07 11:07-0600\n" +"Last-Translator: Jonathan Bustillos \n" +"Language-Team: Debian Spanish \n" +"Language: \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: Gtranslator 2.91.6\n" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "Possible insecure nginx log files" +msgstr "Posibles archivos de registro inseguros de 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 "" +"Los siguientes archivos de registro en el directorio /var/log/nginx son " +"enlaces simbólicos propiedad de 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 "" +"Dado nginx 1.4.4-4 /var/log/nginx era propiedad de www-data. Como resultado, " +"www-data podría enlazar archivos de registro a ubicaciones sensibles, lo que " +"a su vez podría dar lugar a ataques de escalamiento de privilegios. Aunque " +"los permisos de /var/log/nginx están ahora arreglados, es posible que dichos " +"enlaces inseguros ya existan. Por lo tanto, asegúrese de comprobar las " +"ubicaciones anteriores." From 499c94281624967b714aed606c58ee5bd96751e2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 28 Jun 2017 11:21:53 +0300 Subject: [PATCH 008/414] Merge pt translations Thanks: Rui Branco Closes: #858741 --- debian/po/pt.po | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 debian/po/pt.po diff --git a/debian/po/pt.po b/debian/po/pt.po new file mode 100644 index 0000000..c552ab3 --- /dev/null +++ b/debian/po/pt.po @@ -0,0 +1,59 @@ +# Nginx debconf translations +# Copyright (C) 2016 Christos Trochalakis +# This file is distributed under the same license as the nginx package. +# Christos Trochalakis , 2016. +# Rui Branco , initial translation 2017, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: nginx 1.10.3-1\n" +"Report-Msgid-Bugs-To: nginx@packages.debian.org\n" +"POT-Creation-Date: 2016-10-04 20:03+0300\n" +"PO-Revision-Date: 2017-03-14 13:59+0000\n" +"Last-Translator: Rui Branco \n" +"Language-Team: Portuguese \n" +"Language: \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: Gtranslator 2.91.7\n" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "Possible insecure nginx log files" +msgstr "Ficheiros de eventos (log) do nginx possivelmente inseguros" + +#. Type: note +#. Description +#: ../nginx-common.templates:1001 +msgid "" +"The following log files under /var/log/nginx directory are symlinks owned by " +"www-data:" +msgstr "" +"Os seguintes ficheiros de eventos da pasta /var/log/nginx são ligações " +"simbólicas (symlinks) detidos por 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 "" +"Desde a versão 1.4.4-4 do nginx, o ficheiro /var/log/nginx é detido pelo www-" +"data. Como resultado o www-data pode criar ligações simbólicas de ficheiros " +"de eventos para locais sensíveis, o que poderá levar a uma escalada de " +"ataques de privilégios. Apesar das permissões de /var/log/nginx estarem " +"agora seguras, é possível que tais ligações inseguras já existam. Verifique " +"por favor os locais acima mencionados." From 22fe275a6565ccc88960b47a2dbe511989901d6b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 28 Jun 2017 19:00:33 +0300 Subject: [PATCH 009/414] Bump Standards to to 4.0.0 --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 03b05ce..b260ccb 100644 --- a/debian/control +++ b/debian/control @@ -25,7 +25,7 @@ Build-Depends: autotools-dev, po-debconf, quilt, zlib1g-dev -Standards-Version: 3.9.8.0 +Standards-Version: 4.0.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git From 1dc67ccb2acbb534a1105db677fc92e9a49a41fc Mon Sep 17 00:00:00 2001 From: Nicolas Dandrimont Date: Sat, 24 Jun 2017 21:57:31 +0200 Subject: [PATCH 010/414] Introduce libnginx-mod-rtmp third party module We choose not to include rtmp in nginx-extras for now. Minor changes by Chistos Trochalakis Closes: #843777 --- debian/control | 14 + debian/copyright | 4 + debian/libnginx-mod-rtmp.docs | 1 + debian/libnginx-mod-rtmp.examples | 1 + debian/libnginx-mod-rtmp.nginx | 13 + debian/libnginx-mod.conf/mod-rtmp.conf | 1 + debian/modules/README.Modules-versions | 5 + debian/modules/nginx-rtmp/AUTHORS | 8 + debian/modules/nginx-rtmp/LICENSE | 22 + debian/modules/nginx-rtmp/README.md | 332 +++ debian/modules/nginx-rtmp/config | 133 + .../nginx-rtmp/dash/ngx_rtmp_dash_module.c | 1536 ++++++++++ debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c | 1167 ++++++++ debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h | 52 + debian/modules/nginx-rtmp/doc/README.md | 2 + .../nginx-rtmp/hls/ngx_rtmp_hls_module.c | 2458 ++++++++++++++++ .../modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c | 399 +++ .../modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h | 46 + debian/modules/nginx-rtmp/ngx_rtmp.c | 861 ++++++ debian/modules/nginx-rtmp/ngx_rtmp.h | 622 ++++ .../nginx-rtmp/ngx_rtmp_access_module.c | 471 +++ debian/modules/nginx-rtmp/ngx_rtmp_amf.c | 645 ++++ debian/modules/nginx-rtmp/ngx_rtmp_amf.h | 71 + .../nginx-rtmp/ngx_rtmp_auto_push_module.c | 578 ++++ .../modules/nginx-rtmp/ngx_rtmp_bandwidth.c | 26 + .../modules/nginx-rtmp/ngx_rtmp_bandwidth.h | 31 + debian/modules/nginx-rtmp/ngx_rtmp_bitop.c | 63 + debian/modules/nginx-rtmp/ngx_rtmp_bitop.h | 46 + .../modules/nginx-rtmp/ngx_rtmp_cmd_module.c | 856 ++++++ .../modules/nginx-rtmp/ngx_rtmp_cmd_module.h | 151 + .../nginx-rtmp/ngx_rtmp_codec_module.c | 956 ++++++ .../nginx-rtmp/ngx_rtmp_codec_module.h | 87 + .../nginx-rtmp/ngx_rtmp_control_module.c | 732 +++++ .../modules/nginx-rtmp/ngx_rtmp_core_module.c | 755 +++++ debian/modules/nginx-rtmp/ngx_rtmp_eval.c | 282 ++ debian/modules/nginx-rtmp/ngx_rtmp_eval.h | 44 + .../modules/nginx-rtmp/ngx_rtmp_exec_module.c | 1604 ++++++++++ .../modules/nginx-rtmp/ngx_rtmp_flv_module.c | 675 +++++ debian/modules/nginx-rtmp/ngx_rtmp_handler.c | 895 ++++++ .../modules/nginx-rtmp/ngx_rtmp_handshake.c | 631 ++++ debian/modules/nginx-rtmp/ngx_rtmp_init.c | 329 +++ .../nginx-rtmp/ngx_rtmp_limit_module.c | 205 ++ .../modules/nginx-rtmp/ngx_rtmp_live_module.c | 1153 ++++++++ .../modules/nginx-rtmp/ngx_rtmp_live_module.h | 83 + .../modules/nginx-rtmp/ngx_rtmp_log_module.c | 1016 +++++++ .../modules/nginx-rtmp/ngx_rtmp_mp4_module.c | 2591 +++++++++++++++++ .../nginx-rtmp/ngx_rtmp_netcall_module.c | 725 +++++ .../nginx-rtmp/ngx_rtmp_netcall_module.h | 67 + .../nginx-rtmp/ngx_rtmp_notify_module.c | 1728 +++++++++++ .../modules/nginx-rtmp/ngx_rtmp_play_module.c | 1278 ++++++++ .../modules/nginx-rtmp/ngx_rtmp_play_module.h | 93 + .../nginx-rtmp/ngx_rtmp_proxy_protocol.c | 197 ++ .../nginx-rtmp/ngx_rtmp_proxy_protocol.h | 19 + debian/modules/nginx-rtmp/ngx_rtmp_receive.c | 464 +++ .../nginx-rtmp/ngx_rtmp_record_module.c | 1307 +++++++++ .../nginx-rtmp/ngx_rtmp_record_module.h | 96 + .../nginx-rtmp/ngx_rtmp_relay_module.c | 1690 +++++++++++ .../nginx-rtmp/ngx_rtmp_relay_module.h | 72 + debian/modules/nginx-rtmp/ngx_rtmp_send.c | 635 ++++ debian/modules/nginx-rtmp/ngx_rtmp_shared.c | 126 + .../modules/nginx-rtmp/ngx_rtmp_stat_module.c | 863 ++++++ debian/modules/nginx-rtmp/ngx_rtmp_streams.h | 19 + debian/modules/nginx-rtmp/ngx_rtmp_version.h | 15 + debian/modules/nginx-rtmp/stat.xsl | 355 +++ debian/rules | 2 + debian/tests/control | 3 + 66 files changed, 32407 insertions(+) create mode 100644 debian/libnginx-mod-rtmp.docs create mode 100644 debian/libnginx-mod-rtmp.examples create mode 100755 debian/libnginx-mod-rtmp.nginx create mode 100644 debian/libnginx-mod.conf/mod-rtmp.conf create mode 100644 debian/modules/nginx-rtmp/AUTHORS create mode 100644 debian/modules/nginx-rtmp/LICENSE create mode 100644 debian/modules/nginx-rtmp/README.md create mode 100644 debian/modules/nginx-rtmp/config create mode 100644 debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c create mode 100644 debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c create mode 100644 debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h create mode 100644 debian/modules/nginx-rtmp/doc/README.md create mode 100644 debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c create mode 100644 debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c create mode 100644 debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_access_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_amf.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_amf.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_bitop.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_bitop.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_control_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_core_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_eval.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_eval.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_handler.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_handshake.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_init.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_live_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_live_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_log_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_play_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_play_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_receive.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_record_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_record_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_send.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_shared.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_streams.h create mode 100644 debian/modules/nginx-rtmp/ngx_rtmp_version.h create mode 100644 debian/modules/nginx-rtmp/stat.xsl diff --git a/debian/control b/debian/control index b260ccb..ccb769d 100644 --- a/debian/control +++ b/debian/control @@ -383,3 +383,17 @@ Description: WebDAV missing commands support for Nginx WebDAV support. . WebDAV Ext provides the missing PROPFIND & OPTIONS methods. + +Package: libnginx-mod-rtmp +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: RTMP support for Nginx + The nginx RTMP module is a fully-featured streaming solution implemented in + nginx. + . + It provides the following features: + - Live streaming with RTMP, HLS and MPEG-DASH; + - RTMP Video on Demand from local or HTTP sources; + - Stream relay support via a push or pull model; + - Integrated stream recording; + - and more. diff --git a/debian/copyright b/debian/copyright index 40218cb..78ea210 100644 --- a/debian/copyright +++ b/debian/copyright @@ -107,6 +107,10 @@ Files: debian/modules/ngx_http_substitutions_filter_module/* Copyright: Copyright (C) 2014 by Weibin Yao License: BSD-2-clause +Files: debian/modules/nginx-rtmp/* +Copyright: Copyright (C) 2012-2014, Roman Arutyunyan +License: BSD-2-clause + License: BSD-2-clause All rights reserved. . diff --git a/debian/libnginx-mod-rtmp.docs b/debian/libnginx-mod-rtmp.docs new file mode 100644 index 0000000..8bb7d17 --- /dev/null +++ b/debian/libnginx-mod-rtmp.docs @@ -0,0 +1 @@ +debian/modules/nginx-rtmp/README.md diff --git a/debian/libnginx-mod-rtmp.examples b/debian/libnginx-mod-rtmp.examples new file mode 100644 index 0000000..6748d60 --- /dev/null +++ b/debian/libnginx-mod-rtmp.examples @@ -0,0 +1 @@ +debian/modules/nginx-rtmp/stat.xsl diff --git a/debian/libnginx-mod-rtmp.nginx b/debian/libnginx-mod-rtmp.nginx new file mode 100755 index 0000000..78c206f --- /dev/null +++ b/debian/libnginx-mod-rtmp.nginx @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use File::Basename; + +# Guess module name +$module = basename($0, '.nginx'); +$module =~ s/^libnginx-mod-//; + +$modulepath = $module; +$modulepath =~ s/-/_/g; + +print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; +print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/libnginx-mod.conf/mod-rtmp.conf b/debian/libnginx-mod.conf/mod-rtmp.conf new file mode 100644 index 0000000..4e87e6e --- /dev/null +++ b/debian/libnginx-mod.conf/mod-rtmp.conf @@ -0,0 +1 @@ +load_module modules/ngx_rtmp_module.so; diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 8ad843e..8ed4610 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -61,3 +61,8 @@ README for Modules versions Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module Version: v0.6.4 Patch: dynamic-module.patch + + nginx-rtmp + Homepage: https://github.com/arut/nginx-rtmp-module + rm -r debian/modules/nginx-rtmp-module/test + Version: v1.1.11 diff --git a/debian/modules/nginx-rtmp/AUTHORS b/debian/modules/nginx-rtmp/AUTHORS new file mode 100644 index 0000000..e169dff --- /dev/null +++ b/debian/modules/nginx-rtmp/AUTHORS @@ -0,0 +1,8 @@ +Project author: + + Roman Arutyunyan + Moscow, Russia + + Contacts: + arut@qip.ru + arutyunyan.roman@gmail.com diff --git a/debian/modules/nginx-rtmp/LICENSE b/debian/modules/nginx-rtmp/LICENSE new file mode 100644 index 0000000..15cb1e0 --- /dev/null +++ b/debian/modules/nginx-rtmp/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012-2014, Roman Arutyunyan +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 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 OWNER 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/debian/modules/nginx-rtmp/README.md b/debian/modules/nginx-rtmp/README.md new file mode 100644 index 0000000..b4c9a69 --- /dev/null +++ b/debian/modules/nginx-rtmp/README.md @@ -0,0 +1,332 @@ +# NGINX-based Media Streaming Server +## nginx-rtmp-module + + +### Project blog + + http://nginx-rtmp.blogspot.com + +### Wiki manual + + https://github.com/arut/nginx-rtmp-module/wiki/Directives + +### Google group + + https://groups.google.com/group/nginx-rtmp + + https://groups.google.com/group/nginx-rtmp-ru (Russian) + +### Donation page (Paypal etc) + + http://arut.github.com/nginx-rtmp-module/ + +### Features + +* RTMP/HLS/MPEG-DASH live streaming + +* RTMP Video on demand FLV/MP4, + playing from local filesystem or HTTP + +* Stream relay support for distributed + streaming: push & pull models + +* Recording streams in multiple FLVs + +* H264/AAC support + +* Online transcoding with FFmpeg + +* HTTP callbacks (publish/play/record/update etc) + +* Running external programs on certain events (exec) + +* HTTP control module for recording audio/video and dropping clients + +* Advanced buffering techniques + to keep memory allocations at a minimum + level for faster streaming and low + memory footprint + +* Proved to work with Wirecast, FMS, Wowza, + JWPlayer, FlowPlayer, StrobeMediaPlayback, + ffmpeg, avconv, rtmpdump, flvstreamer + and many more + +* Statistics in XML/XSL in machine- & human- + readable form + +* Linux/FreeBSD/MacOS/Windows + +### Build + +cd to NGINX source directory & run this: + + ./configure --add-module=/path/to/nginx-rtmp-module + make + make install + +Several versions of nginx (1.3.14 - 1.5.0) require http_ssl_module to be +added as well: + + ./configure --add-module=/path/to/nginx-rtmp-module --with-http_ssl_module + +For building debug version of nginx add `--with-debug` + + ./configure --add-module=/path/to-nginx/rtmp-module --with-debug + +[Read more about debug log](https://github.com/arut/nginx-rtmp-module/wiki/Debug-log) + +### Windows limitations + +Windows support is limited. These features are not supported + +* execs +* static pulls +* auto_push + +### RTMP URL format + + rtmp://rtmp.example.com/app[/name] + +app - should match one of application {} + blocks in config + +name - interpreted by each application + can be empty + + +### Multi-worker live streaming + +Module supports multi-worker live +streaming through automatic stream pushing +to nginx workers. This option is toggled with +rtmp_auto_push directive. + + +### Example nginx.conf + + rtmp { + + server { + + listen 1935; + + chunk_size 4000; + + # TV mode: one publisher, many subscribers + application mytv { + + # enable live streaming + live on; + + # record first 1K of stream + record all; + record_path /tmp/av; + record_max_size 1K; + + # append current timestamp to each flv + record_unique on; + + # publish only from localhost + allow publish 127.0.0.1; + deny publish all; + + #allow play all; + } + + # Transcoding (ffmpeg needed) + application big { + live on; + + # On every pusblished stream run this command (ffmpeg) + # with substitutions: $app/${app}, $name/${name} for application & stream name. + # + # This ffmpeg call receives stream from this application & + # reduces the resolution down to 32x32. The stream is the published to + # 'small' application (see below) under the same name. + # + # ffmpeg can do anything with the stream like video/audio + # transcoding, resizing, altering container/codec params etc + # + # Multiple exec lines can be specified. + + exec ffmpeg -re -i rtmp://localhost:1935/$app/$name -vcodec flv -acodec copy -s 32x32 + -f flv rtmp://localhost:1935/small/${name}; + } + + application small { + live on; + # Video with reduced resolution comes here from ffmpeg + } + + application webcam { + live on; + + # Stream from local webcam + exec_static ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264 -an + -f flv rtmp://localhost:1935/webcam/mystream; + } + + application mypush { + live on; + + # Every stream published here + # is automatically pushed to + # these two machines + push rtmp1.example.com; + push rtmp2.example.com:1934; + } + + application mypull { + live on; + + # Pull all streams from remote machine + # and play locally + pull rtmp://rtmp3.example.com pageUrl=www.example.com/index.html; + } + + application mystaticpull { + live on; + + # Static pull is started at nginx start + pull rtmp://rtmp4.example.com pageUrl=www.example.com/index.html name=mystream static; + } + + # video on demand + application vod { + play /var/flvs; + } + + application vod2 { + play /var/mp4s; + } + + # Many publishers, many subscribers + # no checks, no recording + application videochat { + + live on; + + # The following notifications receive all + # the session variables as well as + # particular call arguments in HTTP POST + # request + + # Make HTTP request & use HTTP retcode + # to decide whether to allow publishing + # from this connection or not + on_publish http://localhost:8080/publish; + + # Same with playing + on_play http://localhost:8080/play; + + # Publish/play end (repeats on disconnect) + on_done http://localhost:8080/done; + + # All above mentioned notifications receive + # standard connect() arguments as well as + # play/publish ones. If any arguments are sent + # with GET-style syntax to play & publish + # these are also included. + # Example URL: + # rtmp://localhost/myapp/mystream?a=b&c=d + + # record 10 video keyframes (no audio) every 2 minutes + record keyframes; + record_path /tmp/vc; + record_max_frames 10; + record_interval 2m; + + # Async notify about an flv recorded + on_record_done http://localhost:8080/record_done; + + } + + + # HLS + + # For HLS to work please create a directory in tmpfs (/tmp/hls here) + # for the fragments. The directory contents is served via HTTP (see + # http{} section in config) + # + # Incoming stream must be in H264/AAC. For iPhones use baseline H264 + # profile (see ffmpeg example). + # This example creates RTMP stream from movie ready for HLS: + # + # ffmpeg -loglevel verbose -re -i movie.avi -vcodec libx264 + # -vprofile baseline -acodec libmp3lame -ar 44100 -ac 1 + # -f flv rtmp://localhost:1935/hls/movie + # + # If you need to transcode live stream use 'exec' feature. + # + application hls { + live on; + hls on; + hls_path /tmp/hls; + } + + # MPEG-DASH is similar to HLS + + application dash { + live on; + dash on; + dash_path /tmp/dash; + } + } + } + + # HTTP can be used for accessing RTMP stats + http { + + server { + + listen 8080; + + # This URL provides RTMP statistics in XML + location /stat { + rtmp_stat all; + + # Use this stylesheet to view XML as web page + # in browser + rtmp_stat_stylesheet stat.xsl; + } + + location /stat.xsl { + # XML stylesheet to view RTMP stats. + # Copy stat.xsl wherever you want + # and put the full directory path here + root /path/to/stat.xsl/; + } + + location /hls { + # Serve HLS fragments + types { + application/vnd.apple.mpegurl m3u8; + video/mp2t ts; + } + root /tmp; + add_header Cache-Control no-cache; + } + + location /dash { + # Serve DASH fragments + root /tmp; + add_header Cache-Control no-cache; + } + } + } + + +### Multi-worker streaming example + + rtmp_auto_push on; + + rtmp { + server { + listen 1935; + + application mytv { + live on; + } + } + } diff --git a/debian/modules/nginx-rtmp/config b/debian/modules/nginx-rtmp/config new file mode 100644 index 0000000..51176f3 --- /dev/null +++ b/debian/modules/nginx-rtmp/config @@ -0,0 +1,133 @@ +ngx_addon_name="ngx_rtmp_module" + +RTMP_CORE_MODULES=" \ + ngx_rtmp_module \ + ngx_rtmp_core_module \ + ngx_rtmp_cmd_module \ + ngx_rtmp_codec_module \ + ngx_rtmp_access_module \ + ngx_rtmp_record_module \ + ngx_rtmp_live_module \ + ngx_rtmp_play_module \ + ngx_rtmp_flv_module \ + ngx_rtmp_mp4_module \ + ngx_rtmp_netcall_module \ + ngx_rtmp_relay_module \ + ngx_rtmp_exec_module \ + ngx_rtmp_auto_push_module \ + ngx_rtmp_auto_push_index_module \ + ngx_rtmp_notify_module \ + ngx_rtmp_log_module \ + ngx_rtmp_limit_module \ + ngx_rtmp_hls_module \ + ngx_rtmp_dash_module \ + " + + +RTMP_HTTP_MODULES=" \ + ngx_rtmp_stat_module \ + ngx_rtmp_control_module \ + " + + +RTMP_DEPS=" \ + $ngx_addon_dir/ngx_rtmp_amf.h \ + $ngx_addon_dir/ngx_rtmp_bandwidth.h \ + $ngx_addon_dir/ngx_rtmp_cmd_module.h \ + $ngx_addon_dir/ngx_rtmp_codec_module.h \ + $ngx_addon_dir/ngx_rtmp_eval.h \ + $ngx_addon_dir/ngx_rtmp.h \ + $ngx_addon_dir/ngx_rtmp_version.h \ + $ngx_addon_dir/ngx_rtmp_live_module.h \ + $ngx_addon_dir/ngx_rtmp_netcall_module.h \ + $ngx_addon_dir/ngx_rtmp_play_module.h \ + $ngx_addon_dir/ngx_rtmp_record_module.h \ + $ngx_addon_dir/ngx_rtmp_relay_module.h \ + $ngx_addon_dir/ngx_rtmp_streams.h \ + $ngx_addon_dir/ngx_rtmp_bitop.h \ + $ngx_addon_dir/ngx_rtmp_proxy_protocol.h \ + $ngx_addon_dir/hls/ngx_rtmp_mpegts.h \ + $ngx_addon_dir/dash/ngx_rtmp_mp4.h \ + " + + +RTMP_CORE_SRCS=" \ + $ngx_addon_dir/ngx_rtmp.c \ + $ngx_addon_dir/ngx_rtmp_init.c \ + $ngx_addon_dir/ngx_rtmp_handshake.c \ + $ngx_addon_dir/ngx_rtmp_handler.c \ + $ngx_addon_dir/ngx_rtmp_amf.c \ + $ngx_addon_dir/ngx_rtmp_send.c \ + $ngx_addon_dir/ngx_rtmp_shared.c \ + $ngx_addon_dir/ngx_rtmp_eval.c \ + $ngx_addon_dir/ngx_rtmp_receive.c \ + $ngx_addon_dir/ngx_rtmp_core_module.c \ + $ngx_addon_dir/ngx_rtmp_cmd_module.c \ + $ngx_addon_dir/ngx_rtmp_codec_module.c \ + $ngx_addon_dir/ngx_rtmp_access_module.c \ + $ngx_addon_dir/ngx_rtmp_record_module.c \ + $ngx_addon_dir/ngx_rtmp_live_module.c \ + $ngx_addon_dir/ngx_rtmp_play_module.c \ + $ngx_addon_dir/ngx_rtmp_flv_module.c \ + $ngx_addon_dir/ngx_rtmp_mp4_module.c \ + $ngx_addon_dir/ngx_rtmp_netcall_module.c \ + $ngx_addon_dir/ngx_rtmp_relay_module.c \ + $ngx_addon_dir/ngx_rtmp_bandwidth.c \ + $ngx_addon_dir/ngx_rtmp_exec_module.c \ + $ngx_addon_dir/ngx_rtmp_auto_push_module.c \ + $ngx_addon_dir/ngx_rtmp_notify_module.c \ + $ngx_addon_dir/ngx_rtmp_log_module.c \ + $ngx_addon_dir/ngx_rtmp_limit_module.c \ + $ngx_addon_dir/ngx_rtmp_bitop.c \ + $ngx_addon_dir/ngx_rtmp_proxy_protocol.c \ + $ngx_addon_dir/hls/ngx_rtmp_hls_module.c \ + $ngx_addon_dir/dash/ngx_rtmp_dash_module.c \ + $ngx_addon_dir/hls/ngx_rtmp_mpegts.c \ + $ngx_addon_dir/dash/ngx_rtmp_mp4.c \ + " + + +RTMP_HTTP_SRCS=" \ + $ngx_addon_dir/ngx_rtmp_stat_module.c \ + $ngx_addon_dir/ngx_rtmp_control_module.c \ + " + +if [ -f auto/module ] ; then + ngx_module_incs=$ngx_addon_dir + ngx_module_deps=$RTMP_DEPS + + if [ $ngx_module_link = DYNAMIC ] ; then + ngx_module_name="$RTMP_CORE_MODULES $RTMP_HTTP_MODULES" + ngx_module_srcs="$RTMP_CORE_SRCS $RTMP_HTTP_SRCS" + + . auto/module + + else + ngx_module_type=CORE + ngx_module_name=$RTMP_CORE_MODULES + ngx_module_srcs=$RTMP_CORE_SRCS + + . auto/module + + + ngx_module_type=HTTP + ngx_module_name=$RTMP_HTTP_MODULES + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=$RTMP_HTTP_SRCS + + . auto/module + fi + +else + CORE_MODULES="$CORE_MODULES $RTMP_CORE_MODULES" + HTTP_MODULES="$HTTP_MODULES $RTMP_HTTP_MODULES" + + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $RTMP_DEPS" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $RTMP_CORE_SRCS $RTMP_HTTP_SRCS" + + CFLAGS="$CFLAGS -I$ngx_addon_dir" +fi + +USE_OPENSSL=YES + diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c b/debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c new file mode 100644 index 0000000..2ab294e --- /dev/null +++ b/debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c @@ -0,0 +1,1536 @@ + + +#include +#include +#include +#include +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_mp4.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_stream_begin_pt next_stream_begin; +static ngx_rtmp_stream_eof_pt next_stream_eof; + + +static ngx_int_t ngx_rtmp_dash_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_dash_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s); + + +#define NGX_RTMP_DASH_BUFSIZE (1024*1024) +#define NGX_RTMP_DASH_MAX_MDAT (10*1024*1024) +#define NGX_RTMP_DASH_MAX_SAMPLES 1024 +#define NGX_RTMP_DASH_DIR_ACCESS 0744 + + +typedef struct { + uint32_t timestamp; + uint32_t duration; +} ngx_rtmp_dash_frag_t; + + +typedef struct { + ngx_uint_t id; + ngx_uint_t opened; + ngx_uint_t mdat_size; + ngx_uint_t sample_count; + ngx_uint_t sample_mask; + ngx_fd_t fd; + char type; + uint32_t earliest_pres_time; + uint32_t latest_pres_time; + ngx_rtmp_mp4_sample_t samples[NGX_RTMP_DASH_MAX_SAMPLES]; +} ngx_rtmp_dash_track_t; + + +typedef struct { + ngx_str_t playlist; + ngx_str_t playlist_bak; + ngx_str_t name; + ngx_str_t stream; + ngx_time_t start_time; + + ngx_uint_t nfrags; + ngx_uint_t frag; + ngx_rtmp_dash_frag_t *frags; /* circular 2 * winfrags + 1 */ + + unsigned opened:1; + unsigned has_video:1; + unsigned has_audio:1; + + ngx_file_t video_file; + ngx_file_t audio_file; + + ngx_uint_t id; + + ngx_rtmp_dash_track_t audio; + ngx_rtmp_dash_track_t video; +} ngx_rtmp_dash_ctx_t; + + +typedef struct { + ngx_str_t path; + ngx_msec_t playlen; +} ngx_rtmp_dash_cleanup_t; + + +typedef struct { + ngx_flag_t dash; + ngx_msec_t fraglen; + ngx_msec_t playlen; + ngx_flag_t nested; + ngx_str_t path; + ngx_uint_t winfrags; + ngx_flag_t cleanup; + ngx_path_t *slot; +} ngx_rtmp_dash_app_conf_t; + + +static ngx_command_t ngx_rtmp_dash_commands[] = { + + { ngx_string("dash"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, dash), + NULL }, + + { ngx_string("dash_fragment"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, fraglen), + NULL }, + + { ngx_string("dash_path"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, path), + NULL }, + + { ngx_string("dash_playlist_length"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, playlen), + NULL }, + + { ngx_string("dash_cleanup"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, cleanup), + NULL }, + + { ngx_string("dash_nested"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_dash_app_conf_t, nested), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_dash_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_dash_postconfiguration, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_rtmp_dash_create_app_conf, /* create location configuration */ + ngx_rtmp_dash_merge_app_conf, /* merge location configuration */ +}; + + +ngx_module_t ngx_rtmp_dash_module = { + NGX_MODULE_V1, + &ngx_rtmp_dash_module_ctx, /* module context */ + ngx_rtmp_dash_commands, /* module directives */ + NGX_RTMP_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_rtmp_dash_frag_t * +ngx_rtmp_dash_get_frag(ngx_rtmp_session_t *s, ngx_int_t n) +{ + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + return &ctx->frags[(ctx->frag + n) % (dacf->winfrags * 2 + 1)]; +} + + +static void +ngx_rtmp_dash_next_frag(ngx_rtmp_session_t *s) +{ + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + if (ctx->nfrags == dacf->winfrags) { + ctx->frag++; + } else { + ctx->nfrags++; + } +} + + +static ngx_int_t +ngx_rtmp_dash_rename_file(u_char *src, u_char *dst) +{ + /* rename file with overwrite */ + +#if (NGX_WIN32) + return MoveFileEx((LPCTSTR) src, (LPCTSTR) dst, MOVEFILE_REPLACE_EXISTING); +#else + return ngx_rename_file(src, dst); +#endif +} + + +static ngx_int_t +ngx_rtmp_dash_write_playlist(ngx_rtmp_session_t *s) +{ + char *sep; + u_char *p, *last; + ssize_t n; + ngx_fd_t fd; + struct tm tm; + ngx_str_t noname, *name; + ngx_uint_t i; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_rtmp_dash_frag_t *f; + ngx_rtmp_dash_app_conf_t *dacf; + + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; + static u_char start_time[sizeof("1970-09-28T12:00:00+06:00")]; + static u_char end_time[sizeof("1970-09-28T12:00:00+06:00")]; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (dacf == NULL || ctx == NULL || codec_ctx == NULL) { + return NGX_ERROR; + } + + if (ctx->id == 0) { + ngx_rtmp_dash_write_init_segments(s); + } + + fd = ngx_open_file(ctx->playlist_bak.data, NGX_FILE_WRONLY, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: open failed: '%V'", &ctx->playlist_bak); + return NGX_ERROR; + } + + +#define NGX_RTMP_DASH_MANIFEST_HEADER \ + "\n" \ + "\n" \ + " \n" + + +#define NGX_RTMP_DASH_MANIFEST_VIDEO \ + " \n" \ + " \n" \ + " \n" \ + " \n" + + +#define NGX_RTMP_DASH_MANIFEST_VIDEO_FOOTER \ + " \n" \ + " \n" \ + " \n" \ + " \n" + + +#define NGX_RTMP_DASH_MANIFEST_TIME \ + " \n" + + +#define NGX_RTMP_DASH_MANIFEST_AUDIO \ + " \n" \ + " \n" \ + " \n" \ + " \n" \ + " \n" + + +#define NGX_RTMP_DASH_MANIFEST_AUDIO_FOOTER \ + " \n" \ + " \n" \ + " \n" \ + " \n" + + +#define NGX_RTMP_DASH_MANIFEST_FOOTER \ + " \n" \ + "\n" + + ngx_libc_localtime(ctx->start_time.sec + + ngx_rtmp_dash_get_frag(s, 0)->timestamp / 1000, &tm); + + *ngx_sprintf(start_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, + ctx->start_time.gmtoff < 0 ? '-' : '+', + ngx_abs(ctx->start_time.gmtoff / 60), + ngx_abs(ctx->start_time.gmtoff % 60)) = 0; + + ngx_libc_localtime(ctx->start_time.sec + + (ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->timestamp + + ngx_rtmp_dash_get_frag(s, ctx->nfrags - 1)->duration) / + 1000, &tm); + + *ngx_sprintf(end_time, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + tm.tm_year + 1900, tm.tm_mon + 1, + tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, + ctx->start_time.gmtoff < 0 ? '-' : '+', + ngx_abs(ctx->start_time.gmtoff / 60), + ngx_abs(ctx->start_time.gmtoff % 60)) = 0; + + last = buffer + sizeof(buffer); + + p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_HEADER, + start_time, + end_time, + (ngx_uint_t) (dacf->fraglen / 1000), + (ngx_uint_t) (dacf->fraglen / 1000), + (ngx_uint_t) (dacf->fraglen / 500)); + + n = ngx_write_fd(fd, buffer, p - buffer); + + ngx_str_null(&noname); + + name = (dacf->nested ? &noname : &ctx->name); + sep = (dacf->nested ? "" : "-"); + + if (ctx->has_video) { + p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_VIDEO, + codec_ctx->width, + codec_ctx->height, + codec_ctx->frame_rate, + &ctx->name, + codec_ctx->avc_profile, + codec_ctx->avc_compat, + codec_ctx->avc_level, + codec_ctx->width, + codec_ctx->height, + codec_ctx->frame_rate, + (ngx_uint_t) (codec_ctx->video_data_rate * 1000), + name, sep, + name, sep); + + for (i = 0; i < ctx->nfrags; i++) { + f = ngx_rtmp_dash_get_frag(s, i); + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_TIME, + f->timestamp, f->duration); + } + + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_VIDEO_FOOTER); + + n = ngx_write_fd(fd, buffer, p - buffer); + } + + if (ctx->has_audio) { + p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_AUDIO, + &ctx->name, + codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC ? + (codec_ctx->aac_sbr ? "40.5" : "40.2") : "6b", + codec_ctx->sample_rate, + (ngx_uint_t) (codec_ctx->audio_data_rate * 1000), + name, sep, + name, sep); + + for (i = 0; i < ctx->nfrags; i++) { + f = ngx_rtmp_dash_get_frag(s, i); + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_TIME, + f->timestamp, f->duration); + } + + p = ngx_slprintf(p, last, NGX_RTMP_DASH_MANIFEST_AUDIO_FOOTER); + + n = ngx_write_fd(fd, buffer, p - buffer); + } + + p = ngx_slprintf(buffer, last, NGX_RTMP_DASH_MANIFEST_FOOTER); + n = ngx_write_fd(fd, buffer, p - buffer); + + if (n < 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: write failed: '%V'", &ctx->playlist_bak); + ngx_close_file(fd); + return NGX_ERROR; + } + + ngx_close_file(fd); + + if (ngx_rtmp_dash_rename_file(ctx->playlist_bak.data, ctx->playlist.data) + == NGX_FILE_ERROR) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: rename failed: '%V'->'%V'", + &ctx->playlist_bak, &ctx->playlist); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_write_init_segments(ngx_rtmp_session_t *s) +{ + ngx_fd_t fd; + ngx_int_t rc; + ngx_buf_t b; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (ctx == NULL || codec_ctx == NULL) { + return NGX_ERROR; + } + + /* init video */ + + *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4v") = 0; + + fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: error creating video init file"); + return NGX_ERROR; + } + + b.start = buffer; + b.end = b.start + sizeof(buffer); + b.pos = b.last = b.start; + + ngx_rtmp_mp4_write_ftyp(&b); + ngx_rtmp_mp4_write_moov(s, &b, NGX_RTMP_MP4_VIDEO_TRACK); + + rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start)); + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: writing video init failed"); + } + + ngx_close_file(fd); + + /* init audio */ + + *ngx_sprintf(ctx->stream.data + ctx->stream.len, "init.m4a") = 0; + + fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: error creating dash audio init file"); + return NGX_ERROR; + } + + b.pos = b.last = b.start; + + ngx_rtmp_mp4_write_ftyp(&b); + ngx_rtmp_mp4_write_moov(s, &b, NGX_RTMP_MP4_AUDIO_TRACK); + + rc = ngx_write_fd(fd, b.start, (size_t) (b.last - b.start)); + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: writing audio init failed"); + } + + ngx_close_file(fd); + + return NGX_OK; +} + + +static void +ngx_rtmp_dash_close_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t) +{ + u_char *pos, *pos1; + size_t left; + ssize_t n; + ngx_fd_t fd; + ngx_buf_t b; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_frag_t *f; + + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; + + if (!t->opened) { + return; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: close fragment id=%ui, type=%c, pts=%uD", + t->id, t->type, t->earliest_pres_time); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + b.start = buffer; + b.end = buffer + sizeof(buffer); + b.pos = b.last = b.start; + + ngx_rtmp_mp4_write_styp(&b); + + pos = b.last; + b.last += 44; /* leave room for sidx */ + + ngx_rtmp_mp4_write_moof(&b, t->earliest_pres_time, t->sample_count, + t->samples, t->sample_mask, t->id); + pos1 = b.last; + b.last = pos; + + ngx_rtmp_mp4_write_sidx(&b, t->mdat_size + 8 + (pos1 - (pos + 44)), + t->earliest_pres_time, t->latest_pres_time); + b.last = pos1; + ngx_rtmp_mp4_write_mdat(&b, t->mdat_size + 8); + + /* move the data down to make room for the headers */ + + f = ngx_rtmp_dash_get_frag(s, ctx->nfrags); + + *ngx_sprintf(ctx->stream.data + ctx->stream.len, "%uD.m4%c", + f->timestamp, t->type) = 0; + + fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: error creating dash temp video file"); + goto done; + } + + if (ngx_write_fd(fd, b.pos, (size_t) (b.last - b.pos)) == NGX_ERROR) { + goto done; + } + + left = (size_t) t->mdat_size; + +#if (NGX_WIN32) + if (SetFilePointer(t->fd, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "dash: SetFilePointer error"); + goto done; + } +#else + if (lseek(t->fd, 0, SEEK_SET) == -1) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: lseek error"); + goto done; + } +#endif + + while (left > 0) { + + n = ngx_read_fd(t->fd, buffer, ngx_min(sizeof(buffer), left)); + if (n == NGX_ERROR) { + break; + } + + n = ngx_write_fd(fd, buffer, (size_t) n); + if (n == NGX_ERROR) { + break; + } + + left -= n; + } + +done: + + if (fd != NGX_INVALID_FILE) { + ngx_close_file(fd); + } + + ngx_close_file(t->fd); + + t->fd = NGX_INVALID_FILE; + t->opened = 0; +} + + +static ngx_int_t +ngx_rtmp_dash_close_fragments(ngx_rtmp_session_t *s) +{ + ngx_rtmp_dash_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + if (ctx == NULL || !ctx->opened) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: close fragments"); + + ngx_rtmp_dash_close_fragment(s, &ctx->video); + ngx_rtmp_dash_close_fragment(s, &ctx->audio); + + ngx_rtmp_dash_next_frag(s); + + ngx_rtmp_dash_write_playlist(s); + + ctx->id++; + ctx->opened = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_open_fragment(ngx_rtmp_session_t *s, ngx_rtmp_dash_track_t *t, + ngx_uint_t id, char type) +{ + ngx_rtmp_dash_ctx_t *ctx; + + if (t->opened) { + return NGX_OK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: open fragment id=%ui, type='%c'", id, type); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + *ngx_sprintf(ctx->stream.data + ctx->stream.len, "raw.m4%c", type) = 0; + + t->fd = ngx_open_file(ctx->stream.data, NGX_FILE_RDWR, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (t->fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: error creating fragment file"); + return NGX_ERROR; + } + + t->id = id; + t->type = type; + t->sample_count = 0; + t->earliest_pres_time = 0; + t->latest_pres_time = 0; + t->mdat_size = 0; + t->opened = 1; + + if (type == 'v') { + t->sample_mask = NGX_RTMP_MP4_SAMPLE_SIZE| + NGX_RTMP_MP4_SAMPLE_DURATION| + NGX_RTMP_MP4_SAMPLE_DELAY| + NGX_RTMP_MP4_SAMPLE_KEY; + } else { + t->sample_mask = NGX_RTMP_MP4_SAMPLE_SIZE| + NGX_RTMP_MP4_SAMPLE_DURATION; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_open_fragments(ngx_rtmp_session_t *s) +{ + ngx_rtmp_dash_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: open fragments"); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + if (ctx->opened) { + return NGX_OK; + } + + ngx_rtmp_dash_open_fragment(s, &ctx->video, ctx->id, 'v'); + + ngx_rtmp_dash_open_fragment(s, &ctx->audio, ctx->id, 'a'); + + ctx->opened = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_ensure_directory(ngx_rtmp_session_t *s) +{ + size_t len; + ngx_file_info_t fi; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_app_conf_t *dacf; + + static u_char path[NGX_MAX_PATH + 1]; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + + *ngx_snprintf(path, sizeof(path) - 1, "%V", &dacf->path) = 0; + + if (ngx_file_info(path, &fi) == NGX_FILE_ERROR) { + + if (ngx_errno != NGX_ENOENT) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: " ngx_file_info_n " failed on '%V'", + &dacf->path); + return NGX_ERROR; + } + + /* ENOENT */ + + if (ngx_create_dir(path, NGX_RTMP_DASH_DIR_ACCESS) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: " ngx_create_dir_n " failed on '%V'", + &dacf->path); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: directory '%V' created", &dacf->path); + + } else { + + if (!ngx_is_dir(&fi)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "dash: '%V' exists and is not a directory", + &dacf->path); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: directory '%V' exists", &dacf->path); + } + + if (!dacf->nested) { + return NGX_OK; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + len = dacf->path.len; + if (dacf->path.data[len - 1] == '/') { + len--; + } + + *ngx_snprintf(path, sizeof(path) - 1, "%*s/%V", len, dacf->path.data, + &ctx->name) = 0; + + if (ngx_file_info(path, &fi) != NGX_FILE_ERROR) { + + if (ngx_is_dir(&fi)) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: directory '%s' exists", path); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "dash: '%s' exists and is not a directory", path); + + return NGX_ERROR; + } + + if (ngx_errno != NGX_ENOENT) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: " ngx_file_info_n " failed on '%s'", path); + return NGX_ERROR; + } + + /* NGX_ENOENT */ + + if (ngx_create_dir(path, NGX_RTMP_DASH_DIR_ACCESS) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: " ngx_create_dir_n " failed on '%s'", path); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: directory '%s' created", path); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + u_char *p; + size_t len; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_frag_t *f; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + if (dacf == NULL || !dacf->dash || dacf->path.len == 0) { + goto next; + } + + if (s->auto_pushed) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: publish: name='%s' type='%s'", v->name, v->type); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_dash_ctx_t)); + if (ctx == NULL) { + goto next; + } + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_dash_module); + + } else { + if (ctx->opened) { + goto next; + } + + f = ctx->frags; + ngx_memzero(ctx, sizeof(ngx_rtmp_dash_ctx_t)); + ctx->frags = f; + } + + if (ctx->frags == NULL) { + ctx->frags = ngx_pcalloc(s->connection->pool, + sizeof(ngx_rtmp_dash_frag_t) * + (dacf->winfrags * 2 + 1)); + if (ctx->frags == NULL) { + return NGX_ERROR; + } + } + + ctx->id = 0; + + if (ngx_strstr(v->name, "..")) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "dash: bad stream name: '%s'", v->name); + return NGX_ERROR; + } + + ctx->name.len = ngx_strlen(v->name); + ctx->name.data = ngx_palloc(s->connection->pool, ctx->name.len + 1); + + if (ctx->name.data == NULL) { + return NGX_ERROR; + } + + *ngx_cpymem(ctx->name.data, v->name, ctx->name.len) = 0; + + len = dacf->path.len + 1 + ctx->name.len + sizeof(".mpd"); + if (dacf->nested) { + len += sizeof("/index") - 1; + } + + ctx->playlist.data = ngx_palloc(s->connection->pool, len); + p = ngx_cpymem(ctx->playlist.data, dacf->path.data, dacf->path.len); + + if (p[-1] != '/') { + *p++ = '/'; + } + + p = ngx_cpymem(p, ctx->name.data, ctx->name.len); + + /* + * ctx->stream holds initial part of stream file path + * however the space for the whole stream path + * is allocated + */ + + ctx->stream.len = p - ctx->playlist.data + 1; + ctx->stream.data = ngx_palloc(s->connection->pool, + ctx->stream.len + NGX_INT32_LEN + + sizeof(".m4x")); + + ngx_memcpy(ctx->stream.data, ctx->playlist.data, ctx->stream.len - 1); + ctx->stream.data[ctx->stream.len - 1] = (dacf->nested ? '/' : '-'); + + if (dacf->nested) { + p = ngx_cpymem(p, "/index.mpd", sizeof("/index.mpd") - 1); + } else { + p = ngx_cpymem(p, ".mpd", sizeof(".mpd") - 1); + } + + ctx->playlist.len = p - ctx->playlist.data; + + *p = 0; + + /* playlist bak (new playlist) path */ + + ctx->playlist_bak.data = ngx_palloc(s->connection->pool, + ctx->playlist.len + sizeof(".bak")); + p = ngx_cpymem(ctx->playlist_bak.data, ctx->playlist.data, + ctx->playlist.len); + p = ngx_cpymem(p, ".bak", sizeof(".bak") - 1); + + ctx->playlist_bak.len = p - ctx->playlist_bak.data; + + *p = 0; + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: playlist='%V' playlist_bak='%V' stream_pattern='%V'", + &ctx->playlist, &ctx->playlist_bak, &ctx->stream); + + ctx->start_time = *ngx_cached_time; + + if (ngx_rtmp_dash_ensure_directory(s) != NGX_OK) { + return NGX_ERROR; + } + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_dash_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + + if (dacf == NULL || !dacf->dash || ctx == NULL) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "dash: delete stream"); + + ngx_rtmp_dash_close_fragments(s); + +next: + return next_close_stream(s, v); +} + + +static void +ngx_rtmp_dash_update_fragments(ngx_rtmp_session_t *s, ngx_int_t boundary, + uint32_t timestamp) +{ + int32_t d; + ngx_int_t hit; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_dash_frag_t *f; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + f = ngx_rtmp_dash_get_frag(s, ctx->nfrags); + + d = (int32_t) (timestamp - f->timestamp); + + if (d >= 0) { + + f->duration = timestamp - f->timestamp; + hit = (f->duration >= dacf->fraglen); + + } else { + + /* sometimes clients generate slightly unordered frames */ + + hit = (-d > 1000); + } + + if (ctx->has_video && !hit) { + boundary = 0; + } + + if (!ctx->has_video && ctx->has_audio) { + boundary = hit; + } + + if (ctx->audio.mdat_size >= NGX_RTMP_DASH_MAX_MDAT) { + boundary = 1; + } + + if (ctx->video.mdat_size >= NGX_RTMP_DASH_MAX_MDAT) { + boundary = 1; + } + + if (!ctx->opened) { + boundary = 1; + } + + if (boundary) { + ngx_rtmp_dash_close_fragments(s); + ngx_rtmp_dash_open_fragments(s); + + f = ngx_rtmp_dash_get_frag(s, ctx->nfrags); + f->timestamp = timestamp; + } +} + + +static ngx_int_t +ngx_rtmp_dash_append(ngx_rtmp_session_t *s, ngx_chain_t *in, + ngx_rtmp_dash_track_t *t, ngx_int_t key, uint32_t timestamp, uint32_t delay) +{ + u_char *p; + size_t size, bsize; + ngx_rtmp_mp4_sample_t *smpl; + + static u_char buffer[NGX_RTMP_DASH_BUFSIZE]; + + p = buffer; + size = 0; + + for (; in && size < sizeof(buffer); in = in->next) { + + bsize = (size_t) (in->buf->last - in->buf->pos); + if (size + bsize > sizeof(buffer)) { + bsize = (size_t) (sizeof(buffer) - size); + } + + p = ngx_cpymem(p, in->buf->pos, bsize); + size += bsize; + } + + ngx_rtmp_dash_update_fragments(s, key, timestamp); + + if (t->sample_count == 0) { + t->earliest_pres_time = timestamp; + } + + t->latest_pres_time = timestamp; + + if (t->sample_count < NGX_RTMP_DASH_MAX_SAMPLES) { + + if (ngx_write_fd(t->fd, buffer, size) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: " ngx_write_fd_n " failed"); + return NGX_ERROR; + } + + smpl = &t->samples[t->sample_count]; + + smpl->delay = delay; + smpl->size = (uint32_t) size; + smpl->duration = 0; + smpl->timestamp = timestamp; + smpl->key = (key ? 1 : 0); + + if (t->sample_count > 0) { + smpl = &t->samples[t->sample_count - 1]; + smpl->duration = timestamp - smpl->timestamp; + } + + t->sample_count++; + t->mdat_size += (ngx_uint_t) size; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + u_char htype; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (dacf == NULL || !dacf->dash || ctx == NULL || + codec_ctx == NULL || h->mlen < 2) + { + return NGX_OK; + } + + /* Only AAC is supported */ + + if (codec_ctx->audio_codec_id != NGX_RTMP_AUDIO_AAC || + codec_ctx->aac_header == NULL) + { + return NGX_OK; + } + + if (in->buf->last - in->buf->pos < 2) { + return NGX_ERROR; + } + + /* skip AAC config */ + + htype = in->buf->pos[1]; + if (htype != 1) { + return NGX_OK; + } + + ctx->has_audio = 1; + + /* skip RTMP & AAC headers */ + + in->buf->pos += 2; + + return ngx_rtmp_dash_append(s, in, &ctx->audio, 0, h->timestamp, 0); +} + + +static ngx_int_t +ngx_rtmp_dash_video(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + u_char *p; + uint8_t ftype, htype; + uint32_t delay; + ngx_rtmp_dash_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_rtmp_dash_app_conf_t *dacf; + + dacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_dash_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_dash_module); + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (dacf == NULL || !dacf->dash || ctx == NULL || codec_ctx == NULL || + codec_ctx->avc_header == NULL || h->mlen < 5) + { + return NGX_OK; + } + + /* Only H264 is supported */ + + if (codec_ctx->video_codec_id != NGX_RTMP_VIDEO_H264) { + return NGX_OK; + } + + if (in->buf->last - in->buf->pos < 5) { + return NGX_ERROR; + } + + ftype = (in->buf->pos[0] & 0xf0) >> 4; + + /* skip AVC config */ + + htype = in->buf->pos[1]; + if (htype != 1) { + return NGX_OK; + } + + p = (u_char *) &delay; + + p[0] = in->buf->pos[4]; + p[1] = in->buf->pos[3]; + p[2] = in->buf->pos[2]; + p[3] = 0; + + ctx->has_video = 1; + + /* skip RTMP & H264 headers */ + + in->buf->pos += 5; + + return ngx_rtmp_dash_append(s, in, &ctx->video, ftype == 1, h->timestamp, + delay); +} + + +static ngx_int_t +ngx_rtmp_dash_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) +{ + return next_stream_begin(s, v); +} + + +static ngx_int_t +ngx_rtmp_dash_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_eof_t *v) +{ + ngx_rtmp_dash_close_fragments(s); + + return next_stream_eof(s, v); +} + + +static ngx_int_t +ngx_rtmp_dash_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen) +{ + time_t mtime, max_age; + u_char *p; + u_char path[NGX_MAX_PATH + 1], mpd_path[NGX_MAX_PATH + 1]; + ngx_dir_t dir; + ngx_err_t err; + ngx_str_t name, spath, mpd; + ngx_int_t nentries, nerased; + ngx_file_info_t fi; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "dash: cleanup path='%V' playlen=%M", ppath, playlen); + + if (ngx_open_dir(ppath, &dir) != NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, ngx_errno, + "dash: cleanup open dir failed '%V'", ppath); + return NGX_ERROR; + } + + nentries = 0; + nerased = 0; + + for ( ;; ) { + ngx_set_errno(0); + + if (ngx_read_dir(&dir) == NGX_ERROR) { + err = ngx_errno; + + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, + "dash: cleanup " ngx_close_dir_n " \"%V\" failed", + ppath); + } + + if (err == NGX_ENOMOREFILES) { + return nentries - nerased; + } + + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, err, + "dash: cleanup " ngx_read_dir_n + " '%V' failed", ppath); + return NGX_ERROR; + } + + name.data = ngx_de_name(&dir); + if (name.data[0] == '.') { + continue; + } + + name.len = ngx_de_namelen(&dir); + + p = ngx_snprintf(path, sizeof(path) - 1, "%V/%V", ppath, &name); + *p = 0; + + spath.data = path; + spath.len = p - path; + + nentries++; + + if (!dir.valid_info && ngx_de_info(path, &dir) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, + "dash: cleanup " ngx_de_info_n " \"%V\" failed", + &spath); + + continue; + } + + if (ngx_de_is_dir(&dir)) { + + if (ngx_rtmp_dash_cleanup_dir(&spath, playlen) == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "dash: cleanup dir '%V'", &name); + + /* + * null-termination gets spoiled in win32 + * version of ngx_open_dir + */ + + *p = 0; + + if (ngx_delete_dir(path) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "dash: cleanup " ngx_delete_dir_n + " failed on '%V'", &spath); + } else { + nerased++; + } + } + + continue; + } + + if (!ngx_de_is_file(&dir)) { + continue; + } + + if (name.len >= 8 && name.data[name.len - 8] == 'i' && + name.data[name.len - 7] == 'n' && + name.data[name.len - 6] == 'i' && + name.data[name.len - 5] == 't' && + name.data[name.len - 4] == '.' && + name.data[name.len - 3] == 'm' && + name.data[name.len - 2] == '4') + { + if (name.len == 8) { + ngx_str_set(&mpd, "index"); + } else { + mpd.data = name.data; + mpd.len = name.len - 9; + } + + p = ngx_snprintf(mpd_path, sizeof(mpd_path) - 1, "%V/%V.mpd", + ppath, &mpd); + *p = 0; + + if (ngx_file_info(mpd_path, &fi) != NGX_FILE_ERROR) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "dash: cleanup '%V' delayed, mpd exists '%s'", + &name, mpd_path); + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "dash: cleanup '%V' allowed, mpd missing '%s'", + &name, mpd_path); + + max_age = 0; + + } else if (name.len >= 4 && name.data[name.len - 4] == '.' && + name.data[name.len - 3] == 'm' && + name.data[name.len - 2] == '4' && + name.data[name.len - 1] == 'v') + { + max_age = playlen / 500; + + } else if (name.len >= 4 && name.data[name.len - 4] == '.' && + name.data[name.len - 3] == 'm' && + name.data[name.len - 2] == '4' && + name.data[name.len - 1] == 'a') + { + max_age = playlen / 500; + + } else if (name.len >= 4 && name.data[name.len - 4] == '.' && + name.data[name.len - 3] == 'm' && + name.data[name.len - 2] == 'p' && + name.data[name.len - 1] == 'd') + { + max_age = playlen / 500; + + } else if (name.len >= 4 && name.data[name.len - 4] == '.' && + name.data[name.len - 3] == 'r' && + name.data[name.len - 2] == 'a' && + name.data[name.len - 1] == 'w') + { + max_age = playlen / 1000; + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "dash: cleanup skip unknown file type '%V'", &name); + continue; + } + + mtime = ngx_de_mtime(&dir); + if (mtime + max_age > ngx_cached_time->sec) { + continue; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "dash: cleanup '%V' mtime=%T age=%T", + &name, mtime, ngx_cached_time->sec - mtime); + + if (ngx_delete_file(path) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "dash: cleanup " ngx_delete_file_n " failed on '%V'", + &spath); + continue; + } + + nerased++; + } +} + + +#if (nginx_version >= 1011005) +static ngx_msec_t +#else +static time_t +#endif +ngx_rtmp_dash_cleanup(void *data) +{ + ngx_rtmp_dash_cleanup_t *cleanup = data; + + ngx_rtmp_dash_cleanup_dir(&cleanup->path, cleanup->playlen); + +#if (nginx_version >= 1011005) + return cleanup->playlen * 2; +#else + return cleanup->playlen / 500; +#endif +} + + +static void * +ngx_rtmp_dash_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_dash_app_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_dash_app_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->dash = NGX_CONF_UNSET; + conf->fraglen = NGX_CONF_UNSET_MSEC; + conf->playlen = NGX_CONF_UNSET_MSEC; + conf->cleanup = NGX_CONF_UNSET; + conf->nested = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_rtmp_dash_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_dash_app_conf_t *prev = parent; + ngx_rtmp_dash_app_conf_t *conf = child; + ngx_rtmp_dash_cleanup_t *cleanup; + + ngx_conf_merge_value(conf->dash, prev->dash, 0); + ngx_conf_merge_msec_value(conf->fraglen, prev->fraglen, 5000); + ngx_conf_merge_msec_value(conf->playlen, prev->playlen, 30000); + ngx_conf_merge_value(conf->cleanup, prev->cleanup, 1); + ngx_conf_merge_value(conf->nested, prev->nested, 0); + + if (conf->fraglen) { + conf->winfrags = conf->playlen / conf->fraglen; + } + + /* schedule cleanup */ + + if (conf->dash && conf->path.len && conf->cleanup) { + if (conf->path.data[conf->path.len - 1] == '/') { + conf->path.len--; + } + + cleanup = ngx_pcalloc(cf->pool, sizeof(*cleanup)); + if (cleanup == NULL) { + return NGX_CONF_ERROR; + } + + cleanup->path = conf->path; + cleanup->playlen = conf->playlen; + + conf->slot = ngx_pcalloc(cf->pool, sizeof(*conf->slot)); + if (conf->slot == NULL) { + return NGX_CONF_ERROR; + } + + conf->slot->manager = ngx_rtmp_dash_cleanup; + conf->slot->name = conf->path; + conf->slot->data = cleanup; + conf->slot->conf_file = cf->conf_file->file.name.data; + conf->slot->line = cf->conf_file->line; + + if (ngx_add_path(cf, &conf->slot) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + ngx_conf_merge_str_value(conf->path, prev->path, ""); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_dash_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_handler_pt *h; + ngx_rtmp_core_main_conf_t *cmcf; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]); + *h = ngx_rtmp_dash_video; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]); + *h = ngx_rtmp_dash_audio; + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_dash_publish; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_dash_close_stream; + + next_stream_begin = ngx_rtmp_stream_begin; + ngx_rtmp_stream_begin = ngx_rtmp_dash_stream_begin; + + next_stream_eof = ngx_rtmp_stream_eof; + ngx_rtmp_stream_eof = ngx_rtmp_dash_stream_eof; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c b/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c new file mode 100644 index 0000000..dd680c9 --- /dev/null +++ b/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c @@ -0,0 +1,1167 @@ + + +#include +#include +#include "ngx_rtmp_mp4.h" +#include + + +static ngx_int_t +ngx_rtmp_mp4_field_32(ngx_buf_t *b, uint32_t n) +{ + u_char bytes[4]; + + bytes[0] = ((uint32_t) n >> 24) & 0xFF; + bytes[1] = ((uint32_t) n >> 16) & 0xFF; + bytes[2] = ((uint32_t) n >> 8) & 0xFF; + bytes[3] = (uint32_t) n & 0xFF; + + if (b->last + sizeof(bytes) > b->end) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->last, bytes, sizeof(bytes)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_field_24(ngx_buf_t *b, uint32_t n) +{ + u_char bytes[3]; + + bytes[0] = ((uint32_t) n >> 16) & 0xFF; + bytes[1] = ((uint32_t) n >> 8) & 0xFF; + bytes[2] = (uint32_t) n & 0xFF; + + if (b->last + sizeof(bytes) > b->end) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->last, bytes, sizeof(bytes)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_field_16(ngx_buf_t *b, uint16_t n) +{ + u_char bytes[2]; + + bytes[0] = ((uint32_t) n >> 8) & 0xFF; + bytes[1] = (uint32_t) n & 0xFF; + + if (b->last + sizeof(bytes) > b->end) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->last, bytes, sizeof(bytes)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_field_8(ngx_buf_t *b, uint8_t n) +{ + u_char bytes[1]; + + bytes[0] = n & 0xFF; + + if (b->last + sizeof(bytes) > b->end) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->last, bytes, sizeof(bytes)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_put_descr(ngx_buf_t *b, int tag, size_t size) +{ + ngx_rtmp_mp4_field_8(b, (uint8_t) tag); + ngx_rtmp_mp4_field_8(b, size & 0x7F); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_data(ngx_buf_t *b, void *data, size_t n) +{ + if (b->last + n > b->end) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->last, (u_char *) data, n); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_box(ngx_buf_t *b, const char box[4]) +{ + if (b->last + 4 > b->end) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->last, (u_char *) box, 4); + + return NGX_OK; +} + + +static u_char * +ngx_rtmp_mp4_start_box(ngx_buf_t *b, const char box[4]) +{ + u_char *p; + + p = b->last; + + if (ngx_rtmp_mp4_field_32(b, 0) != NGX_OK) { + return NULL; + } + + if (ngx_rtmp_mp4_box(b, box) != NGX_OK) { + return NULL; + } + + return p; +} + + +static ngx_int_t +ngx_rtmp_mp4_update_box_size(ngx_buf_t *b, u_char *p) +{ + u_char *curpos; + + if (p == NULL) { + return NGX_ERROR; + } + + curpos = b->last; + + b->last = p; + + ngx_rtmp_mp4_field_32(b, (uint32_t) (curpos - p)); + + b->last = curpos; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_matrix(ngx_buf_t *buf, uint32_t a, uint32_t b, uint32_t c, + uint32_t d, uint32_t tx, uint32_t ty) +{ + +/* + * transformation matrix + * |a b u| + * |c d v| + * |tx ty w| + */ + + ngx_rtmp_mp4_field_32(buf, a << 16); /* 16.16 format */ + ngx_rtmp_mp4_field_32(buf, b << 16); /* 16.16 format */ + ngx_rtmp_mp4_field_32(buf, 0); /* u in 2.30 format */ + ngx_rtmp_mp4_field_32(buf, c << 16); /* 16.16 format */ + ngx_rtmp_mp4_field_32(buf, d << 16); /* 16.16 format */ + ngx_rtmp_mp4_field_32(buf, 0); /* v in 2.30 format */ + ngx_rtmp_mp4_field_32(buf, tx << 16); /* 16.16 format */ + ngx_rtmp_mp4_field_32(buf, ty << 16); /* 16.16 format */ + ngx_rtmp_mp4_field_32(buf, 1 << 30); /* w in 2.30 format */ + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "ftyp"); + + /* major brand */ + ngx_rtmp_mp4_box(b, "iso6"); + + /* minor version */ + ngx_rtmp_mp4_field_32(b, 1); + + /* compatible brands */ + ngx_rtmp_mp4_box(b, "isom"); + ngx_rtmp_mp4_box(b, "iso6"); + ngx_rtmp_mp4_box(b, "dash"); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mp4_write_styp(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "styp"); + + /* major brand */ + ngx_rtmp_mp4_box(b, "iso6"); + + /* minor version */ + ngx_rtmp_mp4_field_32(b, 1); + + /* compatible brands */ + ngx_rtmp_mp4_box(b, "isom"); + ngx_rtmp_mp4_box(b, "iso6"); + ngx_rtmp_mp4_box(b, "dash"); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_mvhd(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "mvhd"); + + /* version */ + ngx_rtmp_mp4_field_32(b, 0); + + /* creation time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* modification time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* timescale */ + ngx_rtmp_mp4_field_32(b, 1000); + + /* duration */ + ngx_rtmp_mp4_field_32(b, 0); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0x00010000); + ngx_rtmp_mp4_field_16(b, 0x0100); + ngx_rtmp_mp4_field_16(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + ngx_rtmp_mp4_write_matrix(b, 1, 0, 0, 1, 0, 0); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + /* next track id */ + ngx_rtmp_mp4_field_32(b, 1); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_tkhd(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + pos = ngx_rtmp_mp4_start_box(b, "tkhd"); + + /* version */ + ngx_rtmp_mp4_field_8(b, 0); + + /* flags: TrackEnabled */ + ngx_rtmp_mp4_field_24(b, 0x0000000f); + + /* creation time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* modification time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* track id */ + ngx_rtmp_mp4_field_32(b, 1); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + + /* duration */ + ngx_rtmp_mp4_field_32(b, 0); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + /* reserved */ + ngx_rtmp_mp4_field_16(b, ttype == NGX_RTMP_MP4_VIDEO_TRACK ? 0 : 0x0100); + + /* reserved */ + ngx_rtmp_mp4_field_16(b, 0); + + ngx_rtmp_mp4_write_matrix(b, 1, 0, 0, 1, 0, 0); + + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + ngx_rtmp_mp4_field_32(b, (uint32_t) codec_ctx->width << 16); + ngx_rtmp_mp4_field_32(b, (uint32_t) codec_ctx->height << 16); + } else { + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + } + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_mdhd(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "mdhd"); + + /* version */ + ngx_rtmp_mp4_field_32(b, 0); + + /* creation time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* modification time */ + ngx_rtmp_mp4_field_32(b, 0); + + /* time scale*/ + ngx_rtmp_mp4_field_32(b, 1000); + + /* duration */ + ngx_rtmp_mp4_field_32(b, 0); + + /* lanuguage */ + ngx_rtmp_mp4_field_16(b, 0x15C7); + + /* reserved */ + ngx_rtmp_mp4_field_16(b, 0); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_hdlr(ngx_buf_t *b, ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "hdlr"); + + /* version and flags */ + ngx_rtmp_mp4_field_32(b, 0); + + /* pre defined */ + ngx_rtmp_mp4_field_32(b, 0); + + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + ngx_rtmp_mp4_box(b, "vide"); + } else { + ngx_rtmp_mp4_box(b, "soun"); + } + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + /* video handler string, NULL-terminated */ + ngx_rtmp_mp4_data(b, "VideoHandler", sizeof("VideoHandler")); + } else { + /* sound handler string, NULL-terminated */ + ngx_rtmp_mp4_data(b, "SoundHandler", sizeof("SoundHandler")); + } + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_vmhd(ngx_buf_t *b) +{ + /* size is always 20, apparently */ + ngx_rtmp_mp4_field_32(b, 20); + + ngx_rtmp_mp4_box(b, "vmhd"); + + /* version and flags */ + ngx_rtmp_mp4_field_32(b, 0x01); + + /* reserved (graphics mode=copy) */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_smhd(ngx_buf_t *b) +{ + /* size is always 16, apparently */ + ngx_rtmp_mp4_field_32(b, 16); + + ngx_rtmp_mp4_box(b, "smhd"); + + /* version and flags */ + ngx_rtmp_mp4_field_32(b, 0); + + /* reserved (balance normally=0) */ + ngx_rtmp_mp4_field_16(b, 0); + ngx_rtmp_mp4_field_16(b, 0); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_dref(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "dref"); + + /* version and flags */ + ngx_rtmp_mp4_field_32(b, 0); + + /* entry count */ + ngx_rtmp_mp4_field_32(b, 1); + + /* url size */ + ngx_rtmp_mp4_field_32(b, 0xc); + + ngx_rtmp_mp4_box(b, "url "); + + /* version and flags */ + ngx_rtmp_mp4_field_32(b, 0x00000001); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_dinf(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "dinf"); + + ngx_rtmp_mp4_write_dref(b); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_avcc(ngx_rtmp_session_t *s, ngx_buf_t *b) +{ + u_char *pos, *p; + ngx_chain_t *in; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (codec_ctx == NULL) { + return NGX_ERROR; + } + + in = codec_ctx->avc_header; + if (in == NULL) { + return NGX_ERROR; + } + + pos = ngx_rtmp_mp4_start_box(b, "avcC"); + + /* assume config fits one chunk (highly probable) */ + + /* + * Skip: + * - flv fmt + * - H264 CONF/PICT (0x00) + * - 0 + * - 0 + * - 0 + */ + + p = in->buf->pos + 5; + + if (p < in->buf->last) { + ngx_rtmp_mp4_data(b, p, (size_t) (in->buf->last - p)); + } else { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "dash: invalid avcc received"); + } + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_video(ngx_rtmp_session_t *s, ngx_buf_t *b) +{ + u_char *pos; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + pos = ngx_rtmp_mp4_start_box(b, "avc1"); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_16(b, 0); + + /* data reference index */ + ngx_rtmp_mp4_field_16(b, 1); + + /* codec stream version & revision */ + ngx_rtmp_mp4_field_16(b, 0); + ngx_rtmp_mp4_field_16(b, 0); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + /* width & height */ + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->width); + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->height); + + /* horizontal & vertical resolutions 72 dpi */ + ngx_rtmp_mp4_field_32(b, 0x00480000); + ngx_rtmp_mp4_field_32(b, 0x00480000); + + /* data size */ + ngx_rtmp_mp4_field_32(b, 0); + + /* frame count */ + ngx_rtmp_mp4_field_16(b, 1); + + /* compressor name */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_16(b, 0x18); + ngx_rtmp_mp4_field_16(b, 0xffff); + + ngx_rtmp_mp4_write_avcc(s, b); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_esds(ngx_rtmp_session_t *s, ngx_buf_t *b) +{ + size_t dsi_len; + u_char *pos, *dsi; + ngx_buf_t *db; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (codec_ctx == NULL || codec_ctx->aac_header == NULL) { + return NGX_ERROR; + } + + db = codec_ctx->aac_header->buf; + if (db == NULL) { + return NGX_ERROR; + } + + dsi = db->pos + 2; + if (dsi > db->last) { + return NGX_ERROR; + } + + dsi_len = db->last - dsi; + + pos = ngx_rtmp_mp4_start_box(b, "esds"); + + /* version */ + ngx_rtmp_mp4_field_32(b, 0); + + + /* ES Descriptor */ + + ngx_rtmp_mp4_put_descr(b, 0x03, 23 + dsi_len); + + /* ES_ID */ + ngx_rtmp_mp4_field_16(b, 1); + + /* flags */ + ngx_rtmp_mp4_field_8(b, 0); + + + /* DecoderConfig Descriptor */ + + ngx_rtmp_mp4_put_descr(b, 0x04, 15 + dsi_len); + + /* objectTypeIndication: Audio ISO/IEC 14496-3 (AAC) */ + ngx_rtmp_mp4_field_8(b, 0x40); + + /* streamType: AudioStream */ + ngx_rtmp_mp4_field_8(b, 0x15); + + /* bufferSizeDB */ + ngx_rtmp_mp4_field_24(b, 0); + + /* maxBitrate */ + ngx_rtmp_mp4_field_32(b, 0x0001F151); + + /* avgBitrate */ + ngx_rtmp_mp4_field_32(b, 0x0001F14D); + + + /* DecoderSpecificInfo Descriptor */ + + ngx_rtmp_mp4_put_descr(b, 0x05, dsi_len); + ngx_rtmp_mp4_data(b, dsi, dsi_len); + + + /* SL Descriptor */ + + ngx_rtmp_mp4_put_descr(b, 0x06, 1); + ngx_rtmp_mp4_field_8(b, 0x02); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_audio(ngx_rtmp_session_t *s, ngx_buf_t *b) +{ + u_char *pos; + ngx_rtmp_codec_ctx_t *codec_ctx; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + pos = ngx_rtmp_mp4_start_box(b, "mp4a"); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_16(b, 0); + + /* data reference index */ + ngx_rtmp_mp4_field_16(b, 1); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + ngx_rtmp_mp4_field_32(b, 0); + + /* channel count */ + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->audio_channels); + + /* sample size */ + ngx_rtmp_mp4_field_16(b, (uint16_t) (codec_ctx->sample_size * 8)); + + /* reserved */ + ngx_rtmp_mp4_field_32(b, 0); + + /* time scale */ + ngx_rtmp_mp4_field_16(b, 1000); + + /* sample rate */ + ngx_rtmp_mp4_field_16(b, (uint16_t) codec_ctx->sample_rate); + + ngx_rtmp_mp4_write_esds(s, b); +#if 0 + /* tag size*/ + ngx_rtmp_mp4_field_32(b, 8); + + /* null tag */ + ngx_rtmp_mp4_field_32(b, 0); +#endif + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_stsd(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "stsd"); + + /* version & flags */ + ngx_rtmp_mp4_field_32(b, 0); + + /* entry count */ + ngx_rtmp_mp4_field_32(b, 1); + + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + ngx_rtmp_mp4_write_video(s, b); + } else { + ngx_rtmp_mp4_write_audio(s, b); + } + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_stts(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "stts"); + + ngx_rtmp_mp4_field_32(b, 0); /* version */ + ngx_rtmp_mp4_field_32(b, 0); /* entry count */ + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_stsc(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "stsc"); + + ngx_rtmp_mp4_field_32(b, 0); /* version */ + ngx_rtmp_mp4_field_32(b, 0); /* entry count */ + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_stsz(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "stsz"); + + ngx_rtmp_mp4_field_32(b, 0); /* version */ + ngx_rtmp_mp4_field_32(b, 0); /* entry count */ + ngx_rtmp_mp4_field_32(b, 0); /* moar zeros */ + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_stco(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "stco"); + + ngx_rtmp_mp4_field_32(b, 0); /* version */ + ngx_rtmp_mp4_field_32(b, 0); /* entry count */ + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_stbl(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "stbl"); + + ngx_rtmp_mp4_write_stsd(s, b, ttype); + ngx_rtmp_mp4_write_stts(b); + ngx_rtmp_mp4_write_stsc(b); + ngx_rtmp_mp4_write_stsz(b); + ngx_rtmp_mp4_write_stco(b); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_minf(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "minf"); + + if (ttype == NGX_RTMP_MP4_VIDEO_TRACK) { + ngx_rtmp_mp4_write_vmhd(b); + } else { + ngx_rtmp_mp4_write_smhd(b); + } + + ngx_rtmp_mp4_write_dinf(b); + ngx_rtmp_mp4_write_stbl(s, b, ttype); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_mdia(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "mdia"); + + ngx_rtmp_mp4_write_mdhd(b); + ngx_rtmp_mp4_write_hdlr(b, ttype); + ngx_rtmp_mp4_write_minf(s, b, ttype); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + +static ngx_int_t +ngx_rtmp_mp4_write_trak(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "trak"); + + ngx_rtmp_mp4_write_tkhd(s, b, ttype); + ngx_rtmp_mp4_write_mdia(s, b, ttype); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_mvex(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "mvex"); + + ngx_rtmp_mp4_field_32(b, 0x20); + + ngx_rtmp_mp4_box(b, "trex"); + + /* version & flags */ + ngx_rtmp_mp4_field_32(b, 0); + + /* track id */ + ngx_rtmp_mp4_field_32(b, 1); + + /* default sample description index */ + ngx_rtmp_mp4_field_32(b, 1); + + /* default sample duration */ + ngx_rtmp_mp4_field_32(b, 0); + + /* default sample size, 1024 for AAC */ + ngx_rtmp_mp4_field_32(b, 0); + + /* default sample flags, key on */ + ngx_rtmp_mp4_field_32(b, 0); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "moov"); + + ngx_rtmp_mp4_write_mvhd(b); + ngx_rtmp_mp4_write_mvex(b); + ngx_rtmp_mp4_write_trak(s, b, ttype); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_tfhd(ngx_buf_t *b) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "tfhd"); + + /* version & flags */ + ngx_rtmp_mp4_field_32(b, 0x00020000); + + /* track id */ + ngx_rtmp_mp4_field_32(b, 1); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_tfdt(ngx_buf_t *b, uint32_t earliest_pres_time) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "tfdt"); + + /* version == 1 aka 64 bit integer */ + ngx_rtmp_mp4_field_32(b, 0x00000000); + ngx_rtmp_mp4_field_32(b, earliest_pres_time); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_trun(ngx_buf_t *b, uint32_t sample_count, + ngx_rtmp_mp4_sample_t *samples, ngx_uint_t sample_mask, u_char *moof_pos) +{ + u_char *pos; + uint32_t i, offset, nitems, flags; + + pos = ngx_rtmp_mp4_start_box(b, "trun"); + + nitems = 0; + + /* data offset present */ + flags = 0x01; + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DURATION) { + nitems++; + flags |= 0x000100; + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_SIZE) { + nitems++; + flags |= 0x000200; + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_KEY) { + nitems++; + flags |= 0x000400; + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DELAY) { + nitems++; + flags |= 0x000800; + } + + offset = (pos - moof_pos) + 20 + (sample_count * nitems * 4) + 8; + + ngx_rtmp_mp4_field_32(b, flags); + ngx_rtmp_mp4_field_32(b, sample_count); + ngx_rtmp_mp4_field_32(b, offset); + + for (i = 0; i < sample_count; i++, samples++) { + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DURATION) { + ngx_rtmp_mp4_field_32(b, samples->duration); + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_SIZE) { + ngx_rtmp_mp4_field_32(b, samples->size); + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_KEY) { + ngx_rtmp_mp4_field_32(b, samples->key ? 0x00000000 : 0x00010000); + } + + if (sample_mask & NGX_RTMP_MP4_SAMPLE_DELAY) { + ngx_rtmp_mp4_field_32(b, samples->delay); + } + } + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_traf(ngx_buf_t *b, uint32_t earliest_pres_time, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, + ngx_uint_t sample_mask, u_char *moof_pos) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "traf"); + + ngx_rtmp_mp4_write_tfhd(b); + ngx_rtmp_mp4_write_tfdt(b, earliest_pres_time); + ngx_rtmp_mp4_write_trun(b, sample_count, samples, sample_mask, moof_pos); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_write_mfhd(ngx_buf_t *b, uint32_t index) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "mfhd"); + + /* don't know what this is */ + ngx_rtmp_mp4_field_32(b, 0); + + /* fragment index. */ + ngx_rtmp_mp4_field_32(b, index); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mp4_write_sidx(ngx_buf_t *b, ngx_uint_t reference_size, + uint32_t earliest_pres_time, uint32_t latest_pres_time) +{ + u_char *pos; + uint32_t duration; + + duration = latest_pres_time - earliest_pres_time; + + pos = ngx_rtmp_mp4_start_box(b, "sidx"); + + /* version */ + ngx_rtmp_mp4_field_32(b, 0); + + /* reference id */ + ngx_rtmp_mp4_field_32(b, 1); + + /* timescale */ + ngx_rtmp_mp4_field_32(b, 1000); + + /* earliest presentation time */ + ngx_rtmp_mp4_field_32(b, earliest_pres_time); + + /* first offset */ + ngx_rtmp_mp4_field_32(b, duration); /*TODO*/ + + /* reserved */ + ngx_rtmp_mp4_field_16(b, 0); + + /* reference count = 1 */ + ngx_rtmp_mp4_field_16(b, 1); + + /* 1st bit is reference type, the rest is reference size */ + ngx_rtmp_mp4_field_32(b, reference_size); + + /* subsegment duration */ + ngx_rtmp_mp4_field_32(b, duration); + + /* first bit is startsWithSAP (=1), next 3 bits are SAP type (=001) */ + ngx_rtmp_mp4_field_8(b, 0x90); + + /* SAP delta time */ + ngx_rtmp_mp4_field_24(b, 0); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mp4_write_moof(ngx_buf_t *b, uint32_t earliest_pres_time, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, + ngx_uint_t sample_mask, uint32_t index) +{ + u_char *pos; + + pos = ngx_rtmp_mp4_start_box(b, "moof"); + + ngx_rtmp_mp4_write_mfhd(b, index); + ngx_rtmp_mp4_write_traf(b, earliest_pres_time, sample_count, samples, + sample_mask, pos); + + ngx_rtmp_mp4_update_box_size(b, pos); + + return NGX_OK; +} + + +ngx_uint_t +ngx_rtmp_mp4_write_mdat(ngx_buf_t *b, ngx_uint_t size) +{ + ngx_rtmp_mp4_field_32(b, size); + + ngx_rtmp_mp4_box(b, "mdat"); + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h b/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h new file mode 100644 index 0000000..697b6c8 --- /dev/null +++ b/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h @@ -0,0 +1,52 @@ + + +#ifndef _NGX_RTMP_MP4_H_INCLUDED_ +#define _NGX_RTMP_MP4_H_INCLUDED_ + + +#include +#include +#include + + +#define NGX_RTMP_MP4_SAMPLE_SIZE 0x01 +#define NGX_RTMP_MP4_SAMPLE_DURATION 0x02 +#define NGX_RTMP_MP4_SAMPLE_DELAY 0x04 +#define NGX_RTMP_MP4_SAMPLE_KEY 0x08 + + +typedef struct { + uint32_t size; + uint32_t duration; + uint32_t delay; + uint32_t timestamp; + unsigned key:1; +} ngx_rtmp_mp4_sample_t; + + +typedef enum { + NGX_RTMP_MP4_FILETYPE_INIT, + NGX_RTMP_MP4_FILETYPE_SEG +} ngx_rtmp_mp4_file_type_t; + + +typedef enum { + NGX_RTMP_MP4_VIDEO_TRACK, + NGX_RTMP_MP4_AUDIO_TRACK +} ngx_rtmp_mp4_track_type_t; + + +ngx_int_t ngx_rtmp_mp4_write_ftyp(ngx_buf_t *b); +ngx_int_t ngx_rtmp_mp4_write_styp(ngx_buf_t *b); +ngx_int_t ngx_rtmp_mp4_write_moov(ngx_rtmp_session_t *s, ngx_buf_t *b, + ngx_rtmp_mp4_track_type_t ttype); +ngx_int_t ngx_rtmp_mp4_write_moof(ngx_buf_t *b, uint32_t earliest_pres_time, + uint32_t sample_count, ngx_rtmp_mp4_sample_t *samples, + ngx_uint_t sample_mask, uint32_t index); +ngx_int_t ngx_rtmp_mp4_write_sidx(ngx_buf_t *b, + ngx_uint_t reference_size, uint32_t earliest_pres_time, + uint32_t latest_pres_time); +ngx_uint_t ngx_rtmp_mp4_write_mdat(ngx_buf_t *b, ngx_uint_t size); + + +#endif /* _NGX_RTMP_MP4_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/doc/README.md b/debian/modules/nginx-rtmp/doc/README.md new file mode 100644 index 0000000..407efa7 --- /dev/null +++ b/debian/modules/nginx-rtmp/doc/README.md @@ -0,0 +1,2 @@ +Documentation is available here: +https://github.com/arut/nginx-rtmp-module/wiki diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c b/debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c new file mode 100644 index 0000000..9f6779c --- /dev/null +++ b/debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c @@ -0,0 +1,2458 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include +#include +#include "ngx_rtmp_mpegts.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_stream_begin_pt next_stream_begin; +static ngx_rtmp_stream_eof_pt next_stream_eof; + + +static char * ngx_rtmp_hls_variant(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_rtmp_hls_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_hls_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_hls_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_rtmp_hls_flush_audio(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_hls_ensure_directory(ngx_rtmp_session_t *s, + ngx_str_t *path); + + +#define NGX_RTMP_HLS_BUFSIZE (1024*1024) +#define NGX_RTMP_HLS_DIR_ACCESS 0744 + + +typedef struct { + uint64_t id; + uint64_t key_id; + double duration; + unsigned active:1; + unsigned discont:1; /* before */ +} ngx_rtmp_hls_frag_t; + + +typedef struct { + ngx_str_t suffix; + ngx_array_t args; +} ngx_rtmp_hls_variant_t; + + +typedef struct { + unsigned opened:1; + + ngx_rtmp_mpegts_file_t file; + + ngx_str_t playlist; + ngx_str_t playlist_bak; + ngx_str_t var_playlist; + ngx_str_t var_playlist_bak; + ngx_str_t stream; + ngx_str_t keyfile; + ngx_str_t name; + u_char key[16]; + + uint64_t frag; + uint64_t frag_ts; + uint64_t key_id; + ngx_uint_t nfrags; + ngx_rtmp_hls_frag_t *frags; /* circular 2 * winfrags + 1 */ + + ngx_uint_t audio_cc; + ngx_uint_t video_cc; + ngx_uint_t key_frags; + + uint64_t aframe_base; + uint64_t aframe_num; + + ngx_buf_t *aframe; + uint64_t aframe_pts; + + ngx_rtmp_hls_variant_t *var; +} ngx_rtmp_hls_ctx_t; + + +typedef struct { + ngx_str_t path; + ngx_msec_t playlen; + ngx_uint_t frags_per_key; +} ngx_rtmp_hls_cleanup_t; + + +typedef struct { + ngx_flag_t hls; + ngx_msec_t fraglen; + ngx_msec_t max_fraglen; + ngx_msec_t muxdelay; + ngx_msec_t sync; + ngx_msec_t playlen; + ngx_uint_t winfrags; + ngx_flag_t continuous; + ngx_flag_t nested; + ngx_str_t path; + ngx_uint_t naming; + ngx_uint_t slicing; + ngx_uint_t type; + ngx_path_t *slot; + ngx_msec_t max_audio_delay; + size_t audio_buffer_size; + ngx_flag_t cleanup; + ngx_array_t *variant; + ngx_str_t base_url; + ngx_int_t granularity; + ngx_flag_t keys; + ngx_str_t key_path; + ngx_str_t key_url; + ngx_uint_t frags_per_key; +} ngx_rtmp_hls_app_conf_t; + + +#define NGX_RTMP_HLS_NAMING_SEQUENTIAL 1 +#define NGX_RTMP_HLS_NAMING_TIMESTAMP 2 +#define NGX_RTMP_HLS_NAMING_SYSTEM 3 + + +#define NGX_RTMP_HLS_SLICING_PLAIN 1 +#define NGX_RTMP_HLS_SLICING_ALIGNED 2 + + +#define NGX_RTMP_HLS_TYPE_LIVE 1 +#define NGX_RTMP_HLS_TYPE_EVENT 2 + + +static ngx_conf_enum_t ngx_rtmp_hls_naming_slots[] = { + { ngx_string("sequential"), NGX_RTMP_HLS_NAMING_SEQUENTIAL }, + { ngx_string("timestamp"), NGX_RTMP_HLS_NAMING_TIMESTAMP }, + { ngx_string("system"), NGX_RTMP_HLS_NAMING_SYSTEM }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_enum_t ngx_rtmp_hls_slicing_slots[] = { + { ngx_string("plain"), NGX_RTMP_HLS_SLICING_PLAIN }, + { ngx_string("aligned"), NGX_RTMP_HLS_SLICING_ALIGNED }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_enum_t ngx_rtmp_hls_type_slots[] = { + { ngx_string("live"), NGX_RTMP_HLS_TYPE_LIVE }, + { ngx_string("event"), NGX_RTMP_HLS_TYPE_EVENT }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_rtmp_hls_commands[] = { + + { ngx_string("hls"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, hls), + NULL }, + + { ngx_string("hls_fragment"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, fraglen), + NULL }, + + { ngx_string("hls_max_fragment"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, max_fraglen), + NULL }, + + { ngx_string("hls_path"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, path), + NULL }, + + { ngx_string("hls_playlist_length"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, playlen), + NULL }, + + { ngx_string("hls_muxdelay"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, muxdelay), + NULL }, + + { ngx_string("hls_sync"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, sync), + NULL }, + + { ngx_string("hls_continuous"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, continuous), + NULL }, + + { ngx_string("hls_nested"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, nested), + NULL }, + + { ngx_string("hls_fragment_naming"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, naming), + &ngx_rtmp_hls_naming_slots }, + + { ngx_string("hls_fragment_slicing"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, slicing), + &ngx_rtmp_hls_slicing_slots }, + + { ngx_string("hls_type"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, type), + &ngx_rtmp_hls_type_slots }, + + { ngx_string("hls_max_audio_delay"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, max_audio_delay), + NULL }, + + { ngx_string("hls_audio_buffer_size"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, audio_buffer_size), + NULL }, + + { ngx_string("hls_cleanup"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, cleanup), + NULL }, + + { ngx_string("hls_variant"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_hls_variant, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("hls_base_url"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, base_url), + NULL }, + + { ngx_string("hls_fragment_naming_granularity"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, granularity), + NULL }, + + { ngx_string("hls_keys"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, keys), + NULL }, + + { ngx_string("hls_key_path"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, key_path), + NULL }, + + { ngx_string("hls_key_url"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, key_url), + NULL }, + + { ngx_string("hls_fragments_per_key"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_hls_app_conf_t, frags_per_key), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_hls_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_hls_postconfiguration, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_rtmp_hls_create_app_conf, /* create location configuration */ + ngx_rtmp_hls_merge_app_conf, /* merge location configuration */ +}; + + +ngx_module_t ngx_rtmp_hls_module = { + NGX_MODULE_V1, + &ngx_rtmp_hls_module_ctx, /* module context */ + ngx_rtmp_hls_commands, /* module directives */ + NGX_RTMP_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_rtmp_hls_frag_t * +ngx_rtmp_hls_get_frag(ngx_rtmp_session_t *s, ngx_int_t n) +{ + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_app_conf_t *hacf; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + return &ctx->frags[(ctx->frag + n) % (hacf->winfrags * 2 + 1)]; +} + + +static void +ngx_rtmp_hls_next_frag(ngx_rtmp_session_t *s) +{ + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_app_conf_t *hacf; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + if (ctx->nfrags == hacf->winfrags) { + ctx->frag++; + } else { + ctx->nfrags++; + } +} + + +static ngx_int_t +ngx_rtmp_hls_rename_file(u_char *src, u_char *dst) +{ + /* rename file with overwrite */ + +#if (NGX_WIN32) + return MoveFileEx((LPCTSTR) src, (LPCTSTR) dst, MOVEFILE_REPLACE_EXISTING); +#else + return ngx_rename_file(src, dst); +#endif +} + + +static ngx_int_t +ngx_rtmp_hls_write_variant_playlist(ngx_rtmp_session_t *s) +{ + static u_char buffer[1024]; + + u_char *p, *last; + ssize_t rc; + ngx_fd_t fd; + ngx_str_t *arg; + ngx_uint_t n, k; + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_variant_t *var; + ngx_rtmp_hls_app_conf_t *hacf; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + fd = ngx_open_file(ctx->var_playlist_bak.data, NGX_FILE_WRONLY, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_open_file_n " failed: '%V'", + &ctx->var_playlist_bak); + + return NGX_ERROR; + } + +#define NGX_RTMP_HLS_VAR_HEADER "#EXTM3U\n#EXT-X-VERSION:3\n" + + rc = ngx_write_fd(fd, NGX_RTMP_HLS_VAR_HEADER, + sizeof(NGX_RTMP_HLS_VAR_HEADER) - 1); + if (rc < 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_write_fd_n " failed: '%V'", + &ctx->var_playlist_bak); + ngx_close_file(fd); + return NGX_ERROR; + } + + var = hacf->variant->elts; + for (n = 0; n < hacf->variant->nelts; n++, var++) + { + p = buffer; + last = buffer + sizeof(buffer); + + p = ngx_slprintf(p, last, "#EXT-X-STREAM-INF:PROGRAM-ID=1"); + + arg = var->args.elts; + for (k = 0; k < var->args.nelts; k++, arg++) { + p = ngx_slprintf(p, last, ",%V", arg); + } + + if (p < last) { + *p++ = '\n'; + } + + p = ngx_slprintf(p, last, "%V%*s%V", + &hacf->base_url, + ctx->name.len - ctx->var->suffix.len, ctx->name.data, + &var->suffix); + if (hacf->nested) { + p = ngx_slprintf(p, last, "%s", "/index"); + } + + p = ngx_slprintf(p, last, "%s", ".m3u8\n"); + + rc = ngx_write_fd(fd, buffer, p - buffer); + if (rc < 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_write_fd_n " failed '%V'", + &ctx->var_playlist_bak); + ngx_close_file(fd); + return NGX_ERROR; + } + } + + ngx_close_file(fd); + + if (ngx_rtmp_hls_rename_file(ctx->var_playlist_bak.data, + ctx->var_playlist.data) + == NGX_FILE_ERROR) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: rename failed: '%V'->'%V'", + &ctx->var_playlist_bak, &ctx->var_playlist); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_write_playlist(ngx_rtmp_session_t *s) +{ + static u_char buffer[1024]; + ngx_fd_t fd; + u_char *p, *end; + ngx_rtmp_hls_ctx_t *ctx; + ssize_t n; + ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_hls_frag_t *f; + ngx_uint_t i, max_frag; + ngx_str_t name_part, key_name_part; + uint64_t prev_key_id; + const char *sep, *key_sep; + + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + fd = ngx_open_file(ctx->playlist_bak.data, NGX_FILE_WRONLY, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_open_file_n " failed: '%V'", + &ctx->playlist_bak); + return NGX_ERROR; + } + + max_frag = hacf->fraglen / 1000; + + for (i = 0; i < ctx->nfrags; i++) { + f = ngx_rtmp_hls_get_frag(s, i); + if (f->duration > max_frag) { + max_frag = (ngx_uint_t) (f->duration + .5); + } + } + + p = buffer; + end = p + sizeof(buffer); + + p = ngx_slprintf(p, end, + "#EXTM3U\n" + "#EXT-X-VERSION:3\n" + "#EXT-X-MEDIA-SEQUENCE:%uL\n" + "#EXT-X-TARGETDURATION:%ui\n", + ctx->frag, max_frag); + + if (hacf->type == NGX_RTMP_HLS_TYPE_EVENT) { + p = ngx_slprintf(p, end, "#EXT-X-PLAYLIST-TYPE: EVENT\n"); + } + + n = ngx_write_fd(fd, buffer, p - buffer); + if (n < 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_write_fd_n " failed: '%V'", + &ctx->playlist_bak); + ngx_close_file(fd); + return NGX_ERROR; + } + + sep = hacf->nested ? (hacf->base_url.len ? "/" : "") : "-"; + key_sep = hacf->nested ? (hacf->key_url.len ? "/" : "") : "-"; + + name_part.len = 0; + if (!hacf->nested || hacf->base_url.len) { + name_part = ctx->name; + } + + key_name_part.len = 0; + if (!hacf->nested || hacf->key_url.len) { + key_name_part = ctx->name; + } + + prev_key_id = 0; + + for (i = 0; i < ctx->nfrags; i++) { + f = ngx_rtmp_hls_get_frag(s, i); + + p = buffer; + end = p + sizeof(buffer); + + if (f->discont) { + p = ngx_slprintf(p, end, "#EXT-X-DISCONTINUITY\n"); + } + + if (hacf->keys && (i == 0 || f->key_id != prev_key_id)) { + p = ngx_slprintf(p, end, "#EXT-X-KEY:METHOD=AES-128," + "URI=\"%V%V%s%uL.key\",IV=0x%032XL\n", + &hacf->key_url, &key_name_part, + key_sep, f->key_id, f->key_id); + } + + prev_key_id = f->key_id; + + p = ngx_slprintf(p, end, + "#EXTINF:%.3f,\n" + "%V%V%s%uL.ts\n", + f->duration, &hacf->base_url, &name_part, sep, f->id); + + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: fragment frag=%uL, n=%ui/%ui, duration=%.3f, " + "discont=%i", + ctx->frag, i + 1, ctx->nfrags, f->duration, f->discont); + + n = ngx_write_fd(fd, buffer, p - buffer); + if (n < 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_write_fd_n " failed '%V'", + &ctx->playlist_bak); + ngx_close_file(fd); + return NGX_ERROR; + } + } + + ngx_close_file(fd); + + if (ngx_rtmp_hls_rename_file(ctx->playlist_bak.data, ctx->playlist.data) + == NGX_FILE_ERROR) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: rename failed: '%V'->'%V'", + &ctx->playlist_bak, &ctx->playlist); + return NGX_ERROR; + } + + if (ctx->var) { + return ngx_rtmp_hls_write_variant_playlist(s); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_copy(ngx_rtmp_session_t *s, void *dst, u_char **src, size_t n, + ngx_chain_t **in) +{ + u_char *last; + size_t pn; + + if (*in == NULL) { + return NGX_ERROR; + } + + for ( ;; ) { + last = (*in)->buf->last; + + if ((size_t)(last - *src) >= n) { + if (dst) { + ngx_memcpy(dst, *src, n); + } + + *src += n; + + while (*in && *src == (*in)->buf->last) { + *in = (*in)->next; + if (*in) { + *src = (*in)->buf->pos; + } + } + + return NGX_OK; + } + + pn = last - *src; + + if (dst) { + ngx_memcpy(dst, *src, pn); + dst = (u_char *)dst + pn; + } + + n -= pn; + *in = (*in)->next; + + if (*in == NULL) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: failed to read %uz byte(s)", n); + return NGX_ERROR; + } + + *src = (*in)->buf->pos; + } +} + + +static ngx_int_t +ngx_rtmp_hls_append_aud(ngx_rtmp_session_t *s, ngx_buf_t *out) +{ + static u_char aud_nal[] = { 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0 }; + + if (out->last + sizeof(aud_nal) > out->end) { + return NGX_ERROR; + } + + out->last = ngx_cpymem(out->last, aud_nal, sizeof(aud_nal)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_append_sps_pps(ngx_rtmp_session_t *s, ngx_buf_t *out) +{ + ngx_rtmp_codec_ctx_t *codec_ctx; + u_char *p; + ngx_chain_t *in; + ngx_rtmp_hls_ctx_t *ctx; + int8_t nnals; + uint16_t len, rlen; + ngx_int_t n; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (ctx == NULL || codec_ctx == NULL) { + return NGX_ERROR; + } + + in = codec_ctx->avc_header; + if (in == NULL) { + return NGX_ERROR; + } + + p = in->buf->pos; + + /* + * Skip bytes: + * - flv fmt + * - H264 CONF/PICT (0x00) + * - 0 + * - 0 + * - 0 + * - version + * - profile + * - compatibility + * - level + * - nal bytes + */ + + if (ngx_rtmp_hls_copy(s, NULL, &p, 10, &in) != NGX_OK) { + return NGX_ERROR; + } + + /* number of SPS NALs */ + if (ngx_rtmp_hls_copy(s, &nnals, &p, 1, &in) != NGX_OK) { + return NGX_ERROR; + } + + nnals &= 0x1f; /* 5lsb */ + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: SPS number: %uz", nnals); + + /* SPS */ + for (n = 0; ; ++n) { + for (; nnals; --nnals) { + + /* NAL length */ + if (ngx_rtmp_hls_copy(s, &rlen, &p, 2, &in) != NGX_OK) { + return NGX_ERROR; + } + + ngx_rtmp_rmemcpy(&len, &rlen, 2); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: header NAL length: %uz", (size_t) len); + + /* AnnexB prefix */ + if (out->end - out->last < 4) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: too small buffer for header NAL size"); + return NGX_ERROR; + } + + *out->last++ = 0; + *out->last++ = 0; + *out->last++ = 0; + *out->last++ = 1; + + /* NAL body */ + if (out->end - out->last < len) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: too small buffer for header NAL"); + return NGX_ERROR; + } + + if (ngx_rtmp_hls_copy(s, out->last, &p, len, &in) != NGX_OK) { + return NGX_ERROR; + } + + out->last += len; + } + + if (n == 1) { + break; + } + + /* number of PPS NALs */ + if (ngx_rtmp_hls_copy(s, &nnals, &p, 1, &in) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: PPS number: %uz", nnals); + } + + return NGX_OK; +} + + +static uint64_t +ngx_rtmp_hls_get_fragment_id(ngx_rtmp_session_t *s, uint64_t ts) +{ + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_app_conf_t *hacf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + + switch (hacf->naming) { + + case NGX_RTMP_HLS_NAMING_TIMESTAMP: + return ts; + + case NGX_RTMP_HLS_NAMING_SYSTEM: + return (uint64_t) ngx_cached_time->sec * 1000 + ngx_cached_time->msec; + + default: /* NGX_RTMP_HLS_NAMING_SEQUENTIAL */ + return ctx->frag + ctx->nfrags; + } +} + + +static ngx_int_t +ngx_rtmp_hls_close_fragment(ngx_rtmp_session_t *s) +{ + ngx_rtmp_hls_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + if (ctx == NULL || !ctx->opened) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: close fragment n=%uL", ctx->frag); + + ngx_rtmp_mpegts_close_file(&ctx->file); + + ctx->opened = 0; + + ngx_rtmp_hls_next_frag(s); + + ngx_rtmp_hls_write_playlist(s); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_open_fragment(ngx_rtmp_session_t *s, uint64_t ts, + ngx_int_t discont) +{ + uint64_t id; + ngx_fd_t fd; + ngx_uint_t g; + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_frag_t *f; + ngx_rtmp_hls_app_conf_t *hacf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + if (ctx->opened) { + return NGX_OK; + } + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + + if (ngx_rtmp_hls_ensure_directory(s, &hacf->path) != NGX_OK) { + return NGX_ERROR; + } + + if (hacf->keys && + ngx_rtmp_hls_ensure_directory(s, &hacf->key_path) != NGX_OK) + { + return NGX_ERROR; + } + + id = ngx_rtmp_hls_get_fragment_id(s, ts); + + if (hacf->granularity) { + g = (ngx_uint_t) hacf->granularity; + id = (uint64_t) (id / g) * g; + } + + ngx_sprintf(ctx->stream.data + ctx->stream.len, "%uL.ts%Z", id); + + if (hacf->keys) { + if (ctx->key_frags == 0) { + + ctx->key_frags = hacf->frags_per_key - 1; + ctx->key_id = id; + + if (RAND_bytes(ctx->key, 16) < 0) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: failed to create key"); + return NGX_ERROR; + } + + ngx_sprintf(ctx->keyfile.data + ctx->keyfile.len, "%uL.key%Z", id); + + fd = ngx_open_file(ctx->keyfile.data, NGX_FILE_WRONLY, + NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: failed to open key file '%s'", + ctx->keyfile.data); + return NGX_ERROR; + } + + if (ngx_write_fd(fd, ctx->key, 16) != 16) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: failed to write key file '%s'", + ctx->keyfile.data); + ngx_close_file(fd); + return NGX_ERROR; + } + + ngx_close_file(fd); + + } else { + if (hacf->frags_per_key) { + ctx->key_frags--; + } + + if (ngx_set_file_time(ctx->keyfile.data, 0, ngx_cached_time->sec) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_errno, + ngx_set_file_time_n " '%s' failed", + ctx->keyfile.data); + } + } + } + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: open fragment file='%s', keyfile='%s', " + "frag=%uL, n=%ui, time=%uL, discont=%i", + ctx->stream.data, + ctx->keyfile.data ? ctx->keyfile.data : (u_char *) "", + ctx->frag, ctx->nfrags, ts, discont); + + if (hacf->keys && + ngx_rtmp_mpegts_init_encryption(&ctx->file, ctx->key, 16, ctx->key_id) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: failed to initialize hls encryption"); + return NGX_ERROR; + } + + if (ngx_rtmp_mpegts_open_file(&ctx->file, ctx->stream.data, + s->connection->log) + != NGX_OK) + { + return NGX_ERROR; + } + + ctx->opened = 1; + + f = ngx_rtmp_hls_get_frag(s, ctx->nfrags); + + ngx_memzero(f, sizeof(*f)); + + f->active = 1; + f->discont = discont; + f->id = id; + f->key_id = ctx->key_id; + + ctx->frag_ts = ts; + + /* start fragment with audio to make iPhone happy */ + + ngx_rtmp_hls_flush_audio(s); + + return NGX_OK; +} + + +static void +ngx_rtmp_hls_restore_stream(ngx_rtmp_session_t *s) +{ + ngx_rtmp_hls_ctx_t *ctx; + ngx_file_t file; + ssize_t ret; + off_t offset; + u_char *p, *last, *end, *next, *pa, *pp, c; + ngx_rtmp_hls_frag_t *f; + double duration; + ngx_int_t discont; + uint64_t mag, key_id, base; + static u_char buffer[4096]; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + ngx_memzero(&file, sizeof(file)); + + file.log = s->connection->log; + + ngx_str_set(&file.name, "m3u8"); + + file.fd = ngx_open_file(ctx->playlist.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, + 0); + if (file.fd == NGX_INVALID_FILE) { + return; + } + + offset = 0; + ctx->nfrags = 0; + f = NULL; + duration = 0; + discont = 0; + key_id = 0; + + for ( ;; ) { + + ret = ngx_read_file(&file, buffer, sizeof(buffer), offset); + if (ret <= 0) { + goto done; + } + + p = buffer; + end = buffer + ret; + + for ( ;; ) { + last = ngx_strlchr(p, end, '\n'); + + if (last == NULL) { + if (p == buffer) { + goto done; + } + break; + } + + next = last + 1; + offset += (next - p); + + if (p != last && last[-1] == '\r') { + last--; + } + + +#define NGX_RTMP_MSEQ "#EXT-X-MEDIA-SEQUENCE:" +#define NGX_RTMP_MSEQ_LEN (sizeof(NGX_RTMP_MSEQ) - 1) + + + if (ngx_memcmp(p, NGX_RTMP_MSEQ, NGX_RTMP_MSEQ_LEN) == 0) { + + ctx->frag = (uint64_t) strtod((const char *) + &p[NGX_RTMP_MSEQ_LEN], NULL); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: restore sequence frag=%uL", ctx->frag); + } + + +#define NGX_RTMP_XKEY "#EXT-X-KEY:" +#define NGX_RTMP_XKEY_LEN (sizeof(NGX_RTMP_XKEY) - 1) + + if (ngx_memcmp(p, NGX_RTMP_XKEY, NGX_RTMP_XKEY_LEN) == 0) { + + /* recover key id from initialization vector */ + + key_id = 0; + base = 1; + pp = last - 1; + + for ( ;; ) { + if (pp < p) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: failed to read key id"); + break; + } + + c = *pp; + if (c == 'x') { + break; + } + + if (c >= '0' && c <= '9') { + c -= '0'; + goto next; + } + + c |= 0x20; + + if (c >= 'a' && c <= 'f') { + c -= 'a' - 10; + goto next; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: bad character in key id"); + break; + + next: + + key_id += base * c; + base *= 0x10; + pp--; + } + } + + +#define NGX_RTMP_EXTINF "#EXTINF:" +#define NGX_RTMP_EXTINF_LEN (sizeof(NGX_RTMP_EXTINF) - 1) + + + if (ngx_memcmp(p, NGX_RTMP_EXTINF, NGX_RTMP_EXTINF_LEN) == 0) { + + duration = strtod((const char *) &p[NGX_RTMP_EXTINF_LEN], NULL); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: restore durarion=%.3f", duration); + } + + +#define NGX_RTMP_DISCONT "#EXT-X-DISCONTINUITY" +#define NGX_RTMP_DISCONT_LEN (sizeof(NGX_RTMP_DISCONT) - 1) + + + if (ngx_memcmp(p, NGX_RTMP_DISCONT, NGX_RTMP_DISCONT_LEN) == 0) { + + discont = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: discontinuity"); + } + + /* find '.ts\r' */ + + if (p + 4 <= last && + last[-3] == '.' && last[-2] == 't' && last[-1] == 's') + { + f = ngx_rtmp_hls_get_frag(s, ctx->nfrags); + + ngx_memzero(f, sizeof(*f)); + + f->duration = duration; + f->discont = discont; + f->active = 1; + f->id = 0; + + discont = 0; + + mag = 1; + for (pa = last - 4; pa >= p; pa--) { + if (*pa < '0' || *pa > '9') { + break; + } + f->id += (*pa - '0') * mag; + mag *= 10; + } + + f->key_id = key_id; + + ngx_rtmp_hls_next_frag(s); + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: restore fragment '%*s' id=%uL, " + "duration=%.3f, frag=%uL, nfrags=%ui", + (size_t) (last - p), p, f->id, f->duration, + ctx->frag, ctx->nfrags); + } + + p = next; + } + } + +done: + ngx_close_file(file.fd); +} + + +static ngx_int_t +ngx_rtmp_hls_ensure_directory(ngx_rtmp_session_t *s, ngx_str_t *path) +{ + size_t len; + ngx_file_info_t fi; + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_app_conf_t *hacf; + + static u_char zpath[NGX_MAX_PATH + 1]; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + + if (path->len + 1 > sizeof(zpath)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "hls: too long path"); + return NGX_ERROR; + } + + ngx_snprintf(zpath, sizeof(zpath), "%V%Z", path); + + if (ngx_file_info(zpath, &fi) == NGX_FILE_ERROR) { + + if (ngx_errno != NGX_ENOENT) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_file_info_n " failed on '%V'", path); + return NGX_ERROR; + } + + /* ENOENT */ + + if (ngx_create_dir(zpath, NGX_RTMP_HLS_DIR_ACCESS) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_create_dir_n " failed on '%V'", path); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: directory '%V' created", path); + + } else { + + if (!ngx_is_dir(&fi)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: '%V' exists and is not a directory", path); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: directory '%V' exists", path); + } + + if (!hacf->nested) { + return NGX_OK; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + len = path->len; + if (path->data[len - 1] == '/') { + len--; + } + + if (len + 1 + ctx->name.len + 1 > sizeof(zpath)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "hls: too long path"); + return NGX_ERROR; + } + + ngx_snprintf(zpath, sizeof(zpath) - 1, "%*s/%V%Z", len, path->data, + &ctx->name); + + if (ngx_file_info(zpath, &fi) != NGX_FILE_ERROR) { + + if (ngx_is_dir(&fi)) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: directory '%s' exists", zpath); + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: '%s' exists and is not a directory", zpath); + + return NGX_ERROR; + } + + if (ngx_errno != NGX_ENOENT) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_file_info_n " failed on '%s'", zpath); + return NGX_ERROR; + } + + /* NGX_ENOENT */ + + if (ngx_create_dir(zpath, NGX_RTMP_HLS_DIR_ACCESS) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "hls: " ngx_create_dir_n " failed on '%s'", zpath); + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: directory '%s' created", zpath); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_hls_ctx_t *ctx; + u_char *p, *pp; + ngx_rtmp_hls_frag_t *f; + ngx_buf_t *b; + size_t len; + ngx_rtmp_hls_variant_t *var; + ngx_uint_t n; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + if (hacf == NULL || !hacf->hls || hacf->path.len == 0) { + goto next; + } + + if (s->auto_pushed) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: publish: name='%s' type='%s'", + v->name, v->type); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + if (ctx == NULL) { + + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_hls_ctx_t)); + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_hls_module); + + } else { + + f = ctx->frags; + b = ctx->aframe; + + ngx_memzero(ctx, sizeof(ngx_rtmp_hls_ctx_t)); + + ctx->frags = f; + ctx->aframe = b; + + if (b) { + b->pos = b->last = b->start; + } + } + + if (ctx->frags == NULL) { + ctx->frags = ngx_pcalloc(s->connection->pool, + sizeof(ngx_rtmp_hls_frag_t) * + (hacf->winfrags * 2 + 1)); + if (ctx->frags == NULL) { + return NGX_ERROR; + } + } + + if (ngx_strstr(v->name, "..")) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: bad stream name: '%s'", v->name); + return NGX_ERROR; + } + + ctx->name.len = ngx_strlen(v->name); + ctx->name.data = ngx_palloc(s->connection->pool, ctx->name.len + 1); + + if (ctx->name.data == NULL) { + return NGX_ERROR; + } + + *ngx_cpymem(ctx->name.data, v->name, ctx->name.len) = 0; + + len = hacf->path.len + 1 + ctx->name.len + sizeof(".m3u8"); + if (hacf->nested) { + len += sizeof("/index") - 1; + } + + ctx->playlist.data = ngx_palloc(s->connection->pool, len); + p = ngx_cpymem(ctx->playlist.data, hacf->path.data, hacf->path.len); + + if (p[-1] != '/') { + *p++ = '/'; + } + + p = ngx_cpymem(p, ctx->name.data, ctx->name.len); + + /* + * ctx->stream holds initial part of stream file path + * however the space for the whole stream path + * is allocated + */ + + ctx->stream.len = p - ctx->playlist.data + 1; + ctx->stream.data = ngx_palloc(s->connection->pool, + ctx->stream.len + NGX_INT64_LEN + + sizeof(".ts")); + + ngx_memcpy(ctx->stream.data, ctx->playlist.data, ctx->stream.len - 1); + ctx->stream.data[ctx->stream.len - 1] = (hacf->nested ? '/' : '-'); + + /* varint playlist path */ + + if (hacf->variant) { + var = hacf->variant->elts; + for (n = 0; n < hacf->variant->nelts; n++, var++) { + if (ctx->name.len > var->suffix.len && + ngx_memcmp(var->suffix.data, + ctx->name.data + ctx->name.len - var->suffix.len, + var->suffix.len) + == 0) + { + ctx->var = var; + + len = (size_t) (p - ctx->playlist.data); + + ctx->var_playlist.len = len - var->suffix.len + sizeof(".m3u8") + - 1; + ctx->var_playlist.data = ngx_palloc(s->connection->pool, + ctx->var_playlist.len + 1); + + pp = ngx_cpymem(ctx->var_playlist.data, ctx->playlist.data, + len - var->suffix.len); + pp = ngx_cpymem(pp, ".m3u8", sizeof(".m3u8") - 1); + *pp = 0; + + ctx->var_playlist_bak.len = ctx->var_playlist.len + + sizeof(".bak") - 1; + ctx->var_playlist_bak.data = ngx_palloc(s->connection->pool, + ctx->var_playlist_bak.len + 1); + + pp = ngx_cpymem(ctx->var_playlist_bak.data, + ctx->var_playlist.data, + ctx->var_playlist.len); + pp = ngx_cpymem(pp, ".bak", sizeof(".bak") - 1); + *pp = 0; + + break; + } + } + } + + + /* playlist path */ + + if (hacf->nested) { + p = ngx_cpymem(p, "/index.m3u8", sizeof("/index.m3u8") - 1); + } else { + p = ngx_cpymem(p, ".m3u8", sizeof(".m3u8") - 1); + } + + ctx->playlist.len = p - ctx->playlist.data; + + *p = 0; + + /* playlist bak (new playlist) path */ + + ctx->playlist_bak.data = ngx_palloc(s->connection->pool, + ctx->playlist.len + sizeof(".bak")); + p = ngx_cpymem(ctx->playlist_bak.data, ctx->playlist.data, + ctx->playlist.len); + p = ngx_cpymem(p, ".bak", sizeof(".bak") - 1); + + ctx->playlist_bak.len = p - ctx->playlist_bak.data; + + *p = 0; + + /* key path */ + + if (hacf->keys) { + len = hacf->key_path.len + 1 + ctx->name.len + 1 + NGX_INT64_LEN + + sizeof(".key"); + + ctx->keyfile.data = ngx_palloc(s->connection->pool, len); + if (ctx->keyfile.data == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(ctx->keyfile.data, hacf->key_path.data, + hacf->key_path.len); + + if (p[-1] != '/') { + *p++ = '/'; + } + + p = ngx_cpymem(p, ctx->name.data, ctx->name.len); + *p++ = (hacf->nested ? '/' : '-'); + + ctx->keyfile.len = p - ctx->keyfile.data; + } + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: playlist='%V' playlist_bak='%V' " + "stream_pattern='%V' keyfile_pattern='%V'", + &ctx->playlist, &ctx->playlist_bak, + &ctx->stream, &ctx->keyfile); + + if (hacf->continuous) { + ngx_rtmp_hls_restore_stream(s); + } + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_hls_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_hls_ctx_t *ctx; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + if (hacf == NULL || !hacf->hls || ctx == NULL) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: close stream"); + + ngx_rtmp_hls_close_fragment(s); + +next: + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_hls_parse_aac_header(ngx_rtmp_session_t *s, ngx_uint_t *objtype, + ngx_uint_t *srindex, ngx_uint_t *chconf) +{ + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_chain_t *cl; + u_char *p, b0, b1; + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + cl = codec_ctx->aac_header; + + p = cl->buf->pos; + + if (ngx_rtmp_hls_copy(s, NULL, &p, 2, &cl) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_hls_copy(s, &b0, &p, 1, &cl) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_hls_copy(s, &b1, &p, 1, &cl) != NGX_OK) { + return NGX_ERROR; + } + + *objtype = b0 >> 3; + if (*objtype == 0 || *objtype == 0x1f) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: unsupported adts object type:%ui", *objtype); + return NGX_ERROR; + } + + if (*objtype > 4) { + + /* + * Mark all extended profiles as LC + * to make Android as happy as possible. + */ + + *objtype = 2; + } + + *srindex = ((b0 << 1) & 0x0f) | ((b1 & 0x80) >> 7); + if (*srindex == 0x0f) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: unsupported adts sample rate:%ui", *srindex); + return NGX_ERROR; + } + + *chconf = (b1 >> 3) & 0x0f; + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: aac object_type:%ui, sample_rate_index:%ui, " + "channel_config:%ui", *objtype, *srindex, *chconf); + + return NGX_OK; +} + + +static void +ngx_rtmp_hls_update_fragment(ngx_rtmp_session_t *s, uint64_t ts, + ngx_int_t boundary, ngx_uint_t flush_rate) +{ + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_hls_frag_t *f; + ngx_msec_t ts_frag_len; + ngx_int_t same_frag, force,discont; + ngx_buf_t *b; + int64_t d; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + f = NULL; + force = 0; + discont = 1; + + if (ctx->opened) { + f = ngx_rtmp_hls_get_frag(s, ctx->nfrags); + d = (int64_t) (ts - ctx->frag_ts); + + if (d > (int64_t) hacf->max_fraglen * 90 || d < -90000) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: force fragment split: %.3f sec, ", d / 90000.); + force = 1; + + } else { + f->duration = (ts - ctx->frag_ts) / 90000.; + discont = 0; + } + } + + switch (hacf->slicing) { + case NGX_RTMP_HLS_SLICING_PLAIN: + if (f && f->duration < hacf->fraglen / 1000.) { + boundary = 0; + } + break; + + case NGX_RTMP_HLS_SLICING_ALIGNED: + + ts_frag_len = hacf->fraglen * 90; + same_frag = ctx->frag_ts / ts_frag_len == ts / ts_frag_len; + + if (f && same_frag) { + boundary = 0; + } + + if (f == NULL && (ctx->frag_ts == 0 || same_frag)) { + ctx->frag_ts = ts; + boundary = 0; + } + + break; + } + + if (boundary || force) { + ngx_rtmp_hls_close_fragment(s); + ngx_rtmp_hls_open_fragment(s, ts, discont); + } + + b = ctx->aframe; + if (ctx->opened && b && b->last > b->pos && + ctx->aframe_pts + (uint64_t) hacf->max_audio_delay * 90 / flush_rate + < ts) + { + ngx_rtmp_hls_flush_audio(s); + } +} + + +static ngx_int_t +ngx_rtmp_hls_flush_audio(ngx_rtmp_session_t *s) +{ + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_mpegts_frame_t frame; + ngx_int_t rc; + ngx_buf_t *b; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + if (ctx == NULL || !ctx->opened) { + return NGX_OK; + } + + b = ctx->aframe; + + if (b == NULL || b->pos == b->last) { + return NGX_OK; + } + + ngx_memzero(&frame, sizeof(frame)); + + frame.dts = ctx->aframe_pts; + frame.pts = frame.dts; + frame.cc = ctx->audio_cc; + frame.pid = 0x101; + frame.sid = 0xc0; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: flush audio pts=%uL", frame.pts); + + rc = ngx_rtmp_mpegts_write_frame(&ctx->file, &frame, b); + + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: audio flush failed"); + } + + ctx->audio_cc = frame.cc; + b->pos = b->last = b->start; + + return rc; +} + + +static ngx_int_t +ngx_rtmp_hls_audio(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + uint64_t pts, est_pts; + int64_t dpts; + size_t bsize; + ngx_buf_t *b; + u_char *p; + ngx_uint_t objtype, srindex, chconf, size; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (hacf == NULL || !hacf->hls || ctx == NULL || + codec_ctx == NULL || h->mlen < 2) + { + return NGX_OK; + } + + if (codec_ctx->audio_codec_id != NGX_RTMP_AUDIO_AAC || + codec_ctx->aac_header == NULL || ngx_rtmp_is_codec_header(in)) + { + return NGX_OK; + } + + b = ctx->aframe; + + if (b == NULL) { + + b = ngx_pcalloc(s->connection->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_ERROR; + } + + ctx->aframe = b; + + b->start = ngx_palloc(s->connection->pool, hacf->audio_buffer_size); + if (b->start == NULL) { + return NGX_ERROR; + } + + b->end = b->start + hacf->audio_buffer_size; + b->pos = b->last = b->start; + } + + size = h->mlen - 2 + 7; + pts = (uint64_t) h->timestamp * 90; + + if (b->start + size > b->end) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: too big audio frame"); + return NGX_OK; + } + + /* + * start new fragment here if + * there's no video at all, otherwise + * do it in video handler + */ + + ngx_rtmp_hls_update_fragment(s, pts, codec_ctx->avc_header == NULL, 2); + + if (b->last + size > b->end) { + ngx_rtmp_hls_flush_audio(s); + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: audio pts=%uL", pts); + + if (b->last + 7 > b->end) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: not enough buffer for audio header"); + return NGX_OK; + } + + p = b->last; + b->last += 5; + + /* copy payload */ + + for (; in && b->last < b->end; in = in->next) { + + bsize = in->buf->last - in->buf->pos; + if (b->last + bsize > b->end) { + bsize = b->end - b->last; + } + + b->last = ngx_cpymem(b->last, in->buf->pos, bsize); + } + + /* make up ADTS header */ + + if (ngx_rtmp_hls_parse_aac_header(s, &objtype, &srindex, &chconf) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: aac header error"); + return NGX_OK; + } + + /* we have 5 free bytes + 2 bytes of RTMP frame header */ + + p[0] = 0xff; + p[1] = 0xf1; + p[2] = (u_char) (((objtype - 1) << 6) | (srindex << 2) | + ((chconf & 0x04) >> 2)); + p[3] = (u_char) (((chconf & 0x03) << 6) | ((size >> 11) & 0x03)); + p[4] = (u_char) (size >> 3); + p[5] = (u_char) ((size << 5) | 0x1f); + p[6] = 0xfc; + + if (p != b->start) { + ctx->aframe_num++; + return NGX_OK; + } + + ctx->aframe_pts = pts; + + if (!hacf->sync || codec_ctx->sample_rate == 0) { + return NGX_OK; + } + + /* align audio frames */ + + /* TODO: We assume here AAC frame size is 1024 + * Need to handle AAC frames with frame size of 960 */ + + est_pts = ctx->aframe_base + ctx->aframe_num * 90000 * 1024 / + codec_ctx->sample_rate; + dpts = (int64_t) (est_pts - pts); + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: audio sync dpts=%L (%.5fs)", + dpts, dpts / 90000.); + + if (dpts <= (int64_t) hacf->sync * 90 && + dpts >= (int64_t) hacf->sync * -90) + { + ctx->aframe_num++; + ctx->aframe_pts = est_pts; + return NGX_OK; + } + + ctx->aframe_base = pts; + ctx->aframe_num = 1; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: audio sync gap dpts=%L (%.5fs)", + dpts, dpts / 90000.); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_video(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_hls_app_conf_t *hacf; + ngx_rtmp_hls_ctx_t *ctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + u_char *p; + uint8_t fmt, ftype, htype, nal_type, src_nal_type; + uint32_t len, rlen; + ngx_buf_t out, *b; + uint32_t cts; + ngx_rtmp_mpegts_frame_t frame; + ngx_uint_t nal_bytes; + ngx_int_t aud_sent, sps_pps_sent, boundary; + static u_char buffer[NGX_RTMP_HLS_BUFSIZE]; + + hacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_hls_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_hls_module); + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (hacf == NULL || !hacf->hls || ctx == NULL || codec_ctx == NULL || + codec_ctx->avc_header == NULL || h->mlen < 1) + { + return NGX_OK; + } + + /* Only H264 is supported */ + if (codec_ctx->video_codec_id != NGX_RTMP_VIDEO_H264) { + return NGX_OK; + } + + p = in->buf->pos; + if (ngx_rtmp_hls_copy(s, &fmt, &p, 1, &in) != NGX_OK) { + return NGX_ERROR; + } + + /* 1: keyframe (IDR) + * 2: inter frame + * 3: disposable inter frame */ + + ftype = (fmt & 0xf0) >> 4; + + /* H264 HDR/PICT */ + + if (ngx_rtmp_hls_copy(s, &htype, &p, 1, &in) != NGX_OK) { + return NGX_ERROR; + } + + /* proceed only with PICT */ + + if (htype != 1) { + return NGX_OK; + } + + /* 3 bytes: decoder delay */ + + if (ngx_rtmp_hls_copy(s, &cts, &p, 3, &in) != NGX_OK) { + return NGX_ERROR; + } + + cts = ((cts & 0x00FF0000) >> 16) | ((cts & 0x000000FF) << 16) | + (cts & 0x0000FF00); + + ngx_memzero(&out, sizeof(out)); + + out.start = buffer; + out.end = buffer + sizeof(buffer); + out.pos = out.start; + out.last = out.pos; + + nal_bytes = codec_ctx->avc_nal_bytes; + aud_sent = 0; + sps_pps_sent = 0; + + while (in) { + if (ngx_rtmp_hls_copy(s, &rlen, &p, nal_bytes, &in) != NGX_OK) { + return NGX_OK; + } + + len = 0; + ngx_rtmp_rmemcpy(&len, &rlen, nal_bytes); + + if (len == 0) { + continue; + } + + if (ngx_rtmp_hls_copy(s, &src_nal_type, &p, 1, &in) != NGX_OK) { + return NGX_OK; + } + + nal_type = src_nal_type & 0x1f; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: h264 NAL type=%ui, len=%uD", + (ngx_uint_t) nal_type, len); + + if (nal_type >= 7 && nal_type <= 9) { + if (ngx_rtmp_hls_copy(s, NULL, &p, len - 1, &in) != NGX_OK) { + return NGX_ERROR; + } + continue; + } + + if (!aud_sent) { + switch (nal_type) { + case 1: + case 5: + case 6: + if (ngx_rtmp_hls_append_aud(s, &out) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: error appending AUD NAL"); + } + case 9: + aud_sent = 1; + break; + } + } + + switch (nal_type) { + case 1: + sps_pps_sent = 0; + break; + case 5: + if (sps_pps_sent) { + break; + } + if (ngx_rtmp_hls_append_sps_pps(s, &out) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: error appenging SPS/PPS NALs"); + } + sps_pps_sent = 1; + break; + } + + /* AnnexB prefix */ + + if (out.end - out.last < 5) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: not enough buffer for AnnexB prefix"); + return NGX_OK; + } + + /* first AnnexB prefix is long (4 bytes) */ + + if (out.last == out.pos) { + *out.last++ = 0; + } + + *out.last++ = 0; + *out.last++ = 0; + *out.last++ = 1; + *out.last++ = src_nal_type; + + /* NAL body */ + + if (out.end - out.last < (ngx_int_t) len) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: not enough buffer for NAL"); + return NGX_OK; + } + + if (ngx_rtmp_hls_copy(s, out.last, &p, len - 1, &in) != NGX_OK) { + return NGX_ERROR; + } + + out.last += (len - 1); + } + + ngx_memzero(&frame, sizeof(frame)); + + frame.cc = ctx->video_cc; + frame.dts = (uint64_t) h->timestamp * 90; + frame.pts = frame.dts + cts * 90; + frame.pid = 0x100; + frame.sid = 0xe0; + frame.key = (ftype == 1); + + /* + * start new fragment if + * - we have video key frame AND + * - we have audio buffered or have no audio at all or stream is closed + */ + + b = ctx->aframe; + boundary = frame.key && (codec_ctx->aac_header == NULL || !ctx->opened || + (b && b->last > b->pos)); + + ngx_rtmp_hls_update_fragment(s, frame.dts, boundary, 1); + + if (!ctx->opened) { + return NGX_OK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "hls: video pts=%uL, dts=%uL", frame.pts, frame.dts); + + if (ngx_rtmp_mpegts_write_frame(&ctx->file, &frame, &out) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "hls: video frame failed"); + } + + ctx->video_cc = frame.cc; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) +{ + return next_stream_begin(s, v); +} + + +static ngx_int_t +ngx_rtmp_hls_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_eof_t *v) +{ + ngx_rtmp_hls_flush_audio(s); + + ngx_rtmp_hls_close_fragment(s); + + return next_stream_eof(s, v); +} + + +static ngx_int_t +ngx_rtmp_hls_cleanup_dir(ngx_str_t *ppath, ngx_msec_t playlen) +{ + ngx_dir_t dir; + time_t mtime, max_age; + ngx_err_t err; + ngx_str_t name, spath; + u_char *p; + ngx_int_t nentries, nerased; + u_char path[NGX_MAX_PATH + 1]; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "hls: cleanup path='%V' playlen=%M", + ppath, playlen); + + if (ngx_open_dir(ppath, &dir) != NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, ngx_errno, + "hls: cleanup open dir failed '%V'", ppath); + return NGX_ERROR; + } + + nentries = 0; + nerased = 0; + + for ( ;; ) { + ngx_set_errno(0); + + if (ngx_read_dir(&dir) == NGX_ERROR) { + err = ngx_errno; + + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, + "hls: cleanup " ngx_close_dir_n " \"%V\" failed", + ppath); + } + + if (err == NGX_ENOMOREFILES) { + return nentries - nerased; + } + + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, err, + "hls: cleanup " ngx_read_dir_n + " '%V' failed", ppath); + return NGX_ERROR; + } + + name.data = ngx_de_name(&dir); + if (name.data[0] == '.') { + continue; + } + + name.len = ngx_de_namelen(&dir); + + p = ngx_snprintf(path, sizeof(path) - 1, "%V/%V", ppath, &name); + *p = 0; + + spath.data = path; + spath.len = p - path; + + nentries++; + + if (!dir.valid_info && ngx_de_info(path, &dir) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, + "hls: cleanup " ngx_de_info_n " \"%V\" failed", + &spath); + + continue; + } + + if (ngx_de_is_dir(&dir)) { + + if (ngx_rtmp_hls_cleanup_dir(&spath, playlen) == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "hls: cleanup dir '%V'", &name); + + /* + * null-termination gets spoiled in win32 + * version of ngx_open_dir + */ + + *p = 0; + + if (ngx_delete_dir(path) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "hls: cleanup " ngx_delete_dir_n + " failed on '%V'", &spath); + } else { + nerased++; + } + } + + continue; + } + + if (!ngx_de_is_file(&dir)) { + continue; + } + + if (name.len >= 3 && name.data[name.len - 3] == '.' && + name.data[name.len - 2] == 't' && + name.data[name.len - 1] == 's') + { + max_age = playlen / 500; + + } else if (name.len >= 5 && name.data[name.len - 5] == '.' && + name.data[name.len - 4] == 'm' && + name.data[name.len - 3] == '3' && + name.data[name.len - 2] == 'u' && + name.data[name.len - 1] == '8') + { + max_age = playlen / 1000; + + } else if (name.len >= 4 && name.data[name.len - 4] == '.' && + name.data[name.len - 3] == 'k' && + name.data[name.len - 2] == 'e' && + name.data[name.len - 1] == 'y') + { + max_age = playlen / 500; + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "hls: cleanup skip unknown file type '%V'", &name); + continue; + } + + mtime = ngx_de_mtime(&dir); + if (mtime + max_age > ngx_cached_time->sec) { + continue; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, ngx_cycle->log, 0, + "hls: cleanup '%V' mtime=%T age=%T", + &name, mtime, ngx_cached_time->sec - mtime); + + if (ngx_delete_file(path) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno, + "hls: cleanup " ngx_delete_file_n " failed on '%V'", + &spath); + continue; + } + + nerased++; + } +} + + +#if (nginx_version >= 1011005) +static ngx_msec_t +#else +static time_t +#endif +ngx_rtmp_hls_cleanup(void *data) +{ + ngx_rtmp_hls_cleanup_t *cleanup = data; + + ngx_rtmp_hls_cleanup_dir(&cleanup->path, cleanup->playlen); + +#if (nginx_version >= 1011005) + return cleanup->playlen * 2; +#else + return cleanup->playlen / 500; +#endif +} + + +static char * +ngx_rtmp_hls_variant(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_hls_app_conf_t *hacf = conf; + + ngx_str_t *value, *arg; + ngx_uint_t n; + ngx_rtmp_hls_variant_t *var; + + value = cf->args->elts; + + if (hacf->variant == NULL) { + hacf->variant = ngx_array_create(cf->pool, 1, + sizeof(ngx_rtmp_hls_variant_t)); + if (hacf->variant == NULL) { + return NGX_CONF_ERROR; + } + } + + var = ngx_array_push(hacf->variant); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(var, sizeof(ngx_rtmp_hls_variant_t)); + + var->suffix = value[1]; + + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + if (ngx_array_init(&var->args, cf->pool, cf->args->nelts - 2, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + arg = ngx_array_push_n(&var->args, cf->args->nelts - 2); + if (arg == NULL) { + return NGX_CONF_ERROR; + } + + for (n = 2; n < cf->args->nelts; n++) { + *arg++ = value[n]; + } + + return NGX_CONF_OK; +} + + +static void * +ngx_rtmp_hls_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_hls_app_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_hls_app_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->hls = NGX_CONF_UNSET; + conf->fraglen = NGX_CONF_UNSET_MSEC; + conf->max_fraglen = NGX_CONF_UNSET_MSEC; + conf->muxdelay = NGX_CONF_UNSET_MSEC; + conf->sync = NGX_CONF_UNSET_MSEC; + conf->playlen = NGX_CONF_UNSET_MSEC; + conf->continuous = NGX_CONF_UNSET; + conf->nested = NGX_CONF_UNSET; + conf->naming = NGX_CONF_UNSET_UINT; + conf->slicing = NGX_CONF_UNSET_UINT; + conf->type = NGX_CONF_UNSET_UINT; + conf->max_audio_delay = NGX_CONF_UNSET_MSEC; + conf->audio_buffer_size = NGX_CONF_UNSET_SIZE; + conf->cleanup = NGX_CONF_UNSET; + conf->granularity = NGX_CONF_UNSET; + conf->keys = NGX_CONF_UNSET; + conf->frags_per_key = NGX_CONF_UNSET_UINT; + + return conf; +} + + +static char * +ngx_rtmp_hls_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_hls_app_conf_t *prev = parent; + ngx_rtmp_hls_app_conf_t *conf = child; + ngx_rtmp_hls_cleanup_t *cleanup; + + ngx_conf_merge_value(conf->hls, prev->hls, 0); + ngx_conf_merge_msec_value(conf->fraglen, prev->fraglen, 5000); + ngx_conf_merge_msec_value(conf->max_fraglen, prev->max_fraglen, + conf->fraglen * 10); + ngx_conf_merge_msec_value(conf->muxdelay, prev->muxdelay, 700); + ngx_conf_merge_msec_value(conf->sync, prev->sync, 2); + ngx_conf_merge_msec_value(conf->playlen, prev->playlen, 30000); + ngx_conf_merge_value(conf->continuous, prev->continuous, 1); + ngx_conf_merge_value(conf->nested, prev->nested, 0); + ngx_conf_merge_uint_value(conf->naming, prev->naming, + NGX_RTMP_HLS_NAMING_SEQUENTIAL); + ngx_conf_merge_uint_value(conf->slicing, prev->slicing, + NGX_RTMP_HLS_SLICING_PLAIN); + ngx_conf_merge_uint_value(conf->type, prev->type, + NGX_RTMP_HLS_TYPE_LIVE); + ngx_conf_merge_msec_value(conf->max_audio_delay, prev->max_audio_delay, + 300); + ngx_conf_merge_size_value(conf->audio_buffer_size, prev->audio_buffer_size, + NGX_RTMP_HLS_BUFSIZE); + ngx_conf_merge_value(conf->cleanup, prev->cleanup, 1); + ngx_conf_merge_str_value(conf->base_url, prev->base_url, ""); + ngx_conf_merge_value(conf->granularity, prev->granularity, 0); + ngx_conf_merge_value(conf->keys, prev->keys, 0); + ngx_conf_merge_str_value(conf->key_path, prev->key_path, ""); + ngx_conf_merge_str_value(conf->key_url, prev->key_url, ""); + ngx_conf_merge_uint_value(conf->frags_per_key, prev->frags_per_key, 0); + + if (conf->fraglen) { + conf->winfrags = conf->playlen / conf->fraglen; + } + + /* schedule cleanup */ + + if (conf->hls && conf->path.len && conf->cleanup && + conf->type != NGX_RTMP_HLS_TYPE_EVENT) + { + if (conf->path.data[conf->path.len - 1] == '/') { + conf->path.len--; + } + + cleanup = ngx_pcalloc(cf->pool, sizeof(*cleanup)); + if (cleanup == NULL) { + return NGX_CONF_ERROR; + } + + cleanup->path = conf->path; + cleanup->playlen = conf->playlen; + + conf->slot = ngx_pcalloc(cf->pool, sizeof(*conf->slot)); + if (conf->slot == NULL) { + return NGX_CONF_ERROR; + } + + conf->slot->manager = ngx_rtmp_hls_cleanup; + conf->slot->name = conf->path; + conf->slot->data = cleanup; + conf->slot->conf_file = cf->conf_file->file.name.data; + conf->slot->line = cf->conf_file->line; + + if (ngx_add_path(cf, &conf->slot) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + ngx_conf_merge_str_value(conf->path, prev->path, ""); + + if (conf->keys && conf->cleanup && conf->key_path.len && + ngx_strcmp(conf->key_path.data, conf->path.data) != 0 && + conf->type != NGX_RTMP_HLS_TYPE_EVENT) + { + if (conf->key_path.data[conf->key_path.len - 1] == '/') { + conf->key_path.len--; + } + + cleanup = ngx_pcalloc(cf->pool, sizeof(*cleanup)); + if (cleanup == NULL) { + return NGX_CONF_ERROR; + } + + cleanup->path = conf->key_path; + cleanup->playlen = conf->playlen; + + conf->slot = ngx_pcalloc(cf->pool, sizeof(*conf->slot)); + if (conf->slot == NULL) { + return NGX_CONF_ERROR; + } + + conf->slot->manager = ngx_rtmp_hls_cleanup; + conf->slot->name = conf->key_path; + conf->slot->data = cleanup; + conf->slot->conf_file = cf->conf_file->file.name.data; + conf->slot->line = cf->conf_file->line; + + if (ngx_add_path(cf, &conf->slot) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + ngx_conf_merge_str_value(conf->key_path, prev->key_path, ""); + + if (conf->key_path.len == 0) { + conf->key_path = conf->path; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_hls_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]); + *h = ngx_rtmp_hls_video; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]); + *h = ngx_rtmp_hls_audio; + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_hls_publish; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_hls_close_stream; + + next_stream_begin = ngx_rtmp_stream_begin; + ngx_rtmp_stream_begin = ngx_rtmp_hls_stream_begin; + + next_stream_eof = ngx_rtmp_stream_eof; + ngx_rtmp_stream_eof = ngx_rtmp_hls_stream_eof; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c b/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c new file mode 100644 index 0000000..ae66f71 --- /dev/null +++ b/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c @@ -0,0 +1,399 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_mpegts.h" + + +static u_char ngx_rtmp_mpegts_header[] = { + + /* TS */ + 0x47, 0x40, 0x00, 0x10, 0x00, + /* PSI */ + 0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00, + /* PAT */ + 0x00, 0x01, 0xf0, 0x01, + /* CRC */ + 0x2e, 0x70, 0x19, 0x05, + /* stuffing 167 bytes */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + + /* TS */ + 0x47, 0x50, 0x01, 0x10, 0x00, + /* PSI */ + 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00, + /* PMT */ + 0xe1, 0x00, + 0xf0, 0x00, + 0x1b, 0xe1, 0x00, 0xf0, 0x00, /* h264 */ + 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac */ + /*0x03, 0xe1, 0x01, 0xf0, 0x00,*/ /* mp3 */ + /* CRC */ + 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */ + /*0x4e, 0x59, 0x3d, 0x1e,*/ /* crc for mp3 */ + /* stuffing 157 bytes */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + + +/* 700 ms PCR delay */ +#define NGX_RTMP_HLS_DELAY 63000 + + +static ngx_int_t +ngx_rtmp_mpegts_write_file(ngx_rtmp_mpegts_file_t *file, u_char *in, + size_t in_size) +{ + u_char *out; + size_t out_size, n; + ssize_t rc; + + static u_char buf[1024]; + + if (!file->encrypt) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, + "mpegts: write %uz bytes", in_size); + + rc = ngx_write_fd(file->fd, in, in_size); + if (rc < 0) { + return NGX_ERROR; + } + + return NGX_OK; + } + + /* encrypt */ + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, + "mpegts: write %uz encrypted bytes", in_size); + + out = buf; + out_size = sizeof(buf); + + if (file->size > 0 && file->size + in_size >= 16) { + ngx_memcpy(file->buf + file->size, in, 16 - file->size); + + in += 16 - file->size; + in_size -= 16 - file->size; + + AES_cbc_encrypt(file->buf, out, 16, &file->key, file->iv, AES_ENCRYPT); + + out += 16; + out_size -= 16; + + file->size = 0; + } + + for ( ;; ) { + n = in_size & ~0x0f; + + if (n > 0) { + if (n > out_size) { + n = out_size; + } + + AES_cbc_encrypt(in, out, n, &file->key, file->iv, AES_ENCRYPT); + + in += n; + in_size -= n; + + } else if (out == buf) { + break; + } + + rc = ngx_write_fd(file->fd, buf, out - buf + n); + if (rc < 0) { + return NGX_ERROR; + } + + out = buf; + out_size = sizeof(buf); + } + + if (in_size) { + ngx_memcpy(file->buf + file->size, in, in_size); + file->size += in_size; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mpegts_write_header(ngx_rtmp_mpegts_file_t *file) +{ + return ngx_rtmp_mpegts_write_file(file, ngx_rtmp_mpegts_header, + sizeof(ngx_rtmp_mpegts_header)); +} + + +static u_char * +ngx_rtmp_mpegts_write_pcr(u_char *p, uint64_t pcr) +{ + *p++ = (u_char) (pcr >> 25); + *p++ = (u_char) (pcr >> 17); + *p++ = (u_char) (pcr >> 9); + *p++ = (u_char) (pcr >> 1); + *p++ = (u_char) (pcr << 7 | 0x7e); + *p++ = 0; + + return p; +} + + +static u_char * +ngx_rtmp_mpegts_write_pts(u_char *p, ngx_uint_t fb, uint64_t pts) +{ + ngx_uint_t val; + + val = fb << 4 | (((pts >> 30) & 0x07) << 1) | 1; + *p++ = (u_char) val; + + val = (((pts >> 15) & 0x7fff) << 1) | 1; + *p++ = (u_char) (val >> 8); + *p++ = (u_char) val; + + val = (((pts) & 0x7fff) << 1) | 1; + *p++ = (u_char) (val >> 8); + *p++ = (u_char) val; + + return p; +} + + +ngx_int_t +ngx_rtmp_mpegts_write_frame(ngx_rtmp_mpegts_file_t *file, + ngx_rtmp_mpegts_frame_t *f, ngx_buf_t *b) +{ + ngx_uint_t pes_size, header_size, body_size, in_size, stuff_size, flags; + u_char packet[188], *p, *base; + ngx_int_t first, rc; + + ngx_log_debug6(NGX_LOG_DEBUG_CORE, file->log, 0, + "mpegts: pid=%ui, sid=%ui, pts=%uL, " + "dts=%uL, key=%ui, size=%ui", + f->pid, f->sid, f->pts, f->dts, + (ngx_uint_t) f->key, (size_t) (b->last - b->pos)); + + first = 1; + + while (b->pos < b->last) { + p = packet; + + f->cc++; + + *p++ = 0x47; + *p++ = (u_char) (f->pid >> 8); + + if (first) { + p[-1] |= 0x40; + } + + *p++ = (u_char) f->pid; + *p++ = 0x10 | (f->cc & 0x0f); /* payload */ + + if (first) { + + if (f->key) { + packet[3] |= 0x20; /* adaptation */ + + *p++ = 7; /* size */ + *p++ = 0x50; /* random access + PCR */ + + p = ngx_rtmp_mpegts_write_pcr(p, f->dts - NGX_RTMP_HLS_DELAY); + } + + /* PES header */ + + *p++ = 0x00; + *p++ = 0x00; + *p++ = 0x01; + *p++ = (u_char) f->sid; + + header_size = 5; + flags = 0x80; /* PTS */ + + if (f->dts != f->pts) { + header_size += 5; + flags |= 0x40; /* DTS */ + } + + pes_size = (b->last - b->pos) + header_size + 3; + if (pes_size > 0xffff) { + pes_size = 0; + } + + *p++ = (u_char) (pes_size >> 8); + *p++ = (u_char) pes_size; + *p++ = 0x80; /* H222 */ + *p++ = (u_char) flags; + *p++ = (u_char) header_size; + + p = ngx_rtmp_mpegts_write_pts(p, flags >> 6, f->pts + + NGX_RTMP_HLS_DELAY); + + if (f->dts != f->pts) { + p = ngx_rtmp_mpegts_write_pts(p, 1, f->dts + + NGX_RTMP_HLS_DELAY); + } + + first = 0; + } + + body_size = (ngx_uint_t) (packet + sizeof(packet) - p); + in_size = (ngx_uint_t) (b->last - b->pos); + + if (body_size <= in_size) { + ngx_memcpy(p, b->pos, body_size); + b->pos += body_size; + + } else { + stuff_size = (body_size - in_size); + + if (packet[3] & 0x20) { + + /* has adaptation */ + + base = &packet[5] + packet[4]; + p = ngx_movemem(base + stuff_size, base, p - base); + ngx_memset(base, 0xff, stuff_size); + packet[4] += (u_char) stuff_size; + + } else { + + /* no adaptation */ + + packet[3] |= 0x20; + p = ngx_movemem(&packet[4] + stuff_size, &packet[4], + p - &packet[4]); + + packet[4] = (u_char) (stuff_size - 1); + if (stuff_size >= 2) { + packet[5] = 0; + ngx_memset(&packet[6], 0xff, stuff_size - 2); + } + } + + ngx_memcpy(p, b->pos, in_size); + b->pos = b->last; + } + + rc = ngx_rtmp_mpegts_write_file(file, packet, sizeof(packet)); + if (rc != NGX_OK) { + return rc; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file, + u_char *key, size_t key_len, uint64_t iv) +{ + if (AES_set_encrypt_key(key, key_len * 8, &file->key)) { + return NGX_ERROR; + } + + ngx_memzero(file->iv, 8); + + file->iv[8] = (u_char) (iv >> 56); + file->iv[9] = (u_char) (iv >> 48); + file->iv[10] = (u_char) (iv >> 40); + file->iv[11] = (u_char) (iv >> 32); + file->iv[12] = (u_char) (iv >> 24); + file->iv[13] = (u_char) (iv >> 16); + file->iv[14] = (u_char) (iv >> 8); + file->iv[15] = (u_char) (iv); + + file->encrypt = 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path, + ngx_log_t *log) +{ + file->log = log; + + file->fd = ngx_open_file(path, NGX_FILE_WRONLY, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + + if (file->fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, log, ngx_errno, + "hls: error creating fragment file"); + return NGX_ERROR; + } + + file->size = 0; + + if (ngx_rtmp_mpegts_write_header(file) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, log, ngx_errno, + "hls: error writing fragment header"); + ngx_close_file(file->fd); + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_mpegts_close_file(ngx_rtmp_mpegts_file_t *file) +{ + u_char buf[16]; + ssize_t rc; + + if (file->encrypt) { + ngx_memset(file->buf + file->size, 16 - file->size, 16 - file->size); + + AES_cbc_encrypt(file->buf, buf, 16, &file->key, file->iv, AES_ENCRYPT); + + rc = ngx_write_fd(file->fd, buf, 16); + if (rc < 0) { + return NGX_ERROR; + } + } + + ngx_close_file(file->fd); + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h b/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h new file mode 100644 index 0000000..c128a51 --- /dev/null +++ b/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h @@ -0,0 +1,46 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_MPEGTS_H_INCLUDED_ +#define _NGX_RTMP_MPEGTS_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + ngx_fd_t fd; + ngx_log_t *log; + unsigned encrypt:1; + unsigned size:4; + u_char buf[16]; + u_char iv[16]; + AES_KEY key; +} ngx_rtmp_mpegts_file_t; + + +typedef struct { + uint64_t pts; + uint64_t dts; + ngx_uint_t pid; + ngx_uint_t sid; + ngx_uint_t cc; + unsigned key:1; +} ngx_rtmp_mpegts_frame_t; + + +ngx_int_t ngx_rtmp_mpegts_init_encryption(ngx_rtmp_mpegts_file_t *file, + u_char *key, size_t key_len, uint64_t iv); +ngx_int_t ngx_rtmp_mpegts_open_file(ngx_rtmp_mpegts_file_t *file, u_char *path, + ngx_log_t *log); +ngx_int_t ngx_rtmp_mpegts_close_file(ngx_rtmp_mpegts_file_t *file); +ngx_int_t ngx_rtmp_mpegts_write_frame(ngx_rtmp_mpegts_file_t *file, + ngx_rtmp_mpegts_frame_t *f, ngx_buf_t *b); + + +#endif /* _NGX_RTMP_MPEGTS_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp.c b/debian/modules/nginx-rtmp/ngx_rtmp.c new file mode 100644 index 0000000..7d504a0 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp.c @@ -0,0 +1,861 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include +#include "ngx_rtmp.h" + + +static char *ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_rtmp_add_ports(ngx_conf_t *cf, ngx_array_t *ports, + ngx_rtmp_listen_t *listen); +static char *ngx_rtmp_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports); +static ngx_int_t ngx_rtmp_add_addrs(ngx_conf_t *cf, ngx_rtmp_port_t *mport, + ngx_rtmp_conf_addr_t *addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_rtmp_add_addrs6(ngx_conf_t *cf, ngx_rtmp_port_t *mport, + ngx_rtmp_conf_addr_t *addr); +#endif +static ngx_int_t ngx_rtmp_cmp_conf_addrs(const void *one, const void *two); +static ngx_int_t ngx_rtmp_init_events(ngx_conf_t *cf, + ngx_rtmp_core_main_conf_t *cmcf); +static ngx_int_t ngx_rtmp_init_event_handlers(ngx_conf_t *cf, + ngx_rtmp_core_main_conf_t *cmcf); +static char * ngx_rtmp_merge_applications(ngx_conf_t *cf, + ngx_array_t *applications, void **app_conf, ngx_rtmp_module_t *module, + ngx_uint_t ctx_index); +static ngx_int_t ngx_rtmp_init_process(ngx_cycle_t *cycle); + + +#if (nginx_version >= 1007011) +ngx_queue_t ngx_rtmp_init_queue; +#elif (nginx_version >= 1007005) +ngx_thread_volatile ngx_queue_t ngx_rtmp_init_queue; +#else +ngx_thread_volatile ngx_event_t *ngx_rtmp_init_queue; +#endif + + +ngx_uint_t ngx_rtmp_max_module; + + +static ngx_command_t ngx_rtmp_commands[] = { + + { ngx_string("rtmp"), + NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_rtmp_block, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_rtmp_module_ctx = { + ngx_string("rtmp"), + NULL, + NULL +}; + + +ngx_module_t ngx_rtmp_module = { + NGX_MODULE_V1, + &ngx_rtmp_module_ctx, /* module context */ + ngx_rtmp_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_rtmp_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static char * +ngx_rtmp_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_uint_t i, m, mi, s; + ngx_conf_t pcf; + ngx_array_t ports; + ngx_module_t **modules; + ngx_rtmp_listen_t *listen; + ngx_rtmp_module_t *module; + ngx_rtmp_conf_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t *cscf, **cscfp; + ngx_rtmp_core_main_conf_t *cmcf; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + *(ngx_rtmp_conf_ctx_t **) conf = ctx; + + /* count the number of the rtmp modules and set up their indices */ + +#if (nginx_version >= 1009011) + + ngx_rtmp_max_module = ngx_count_modules(cf->cycle, NGX_RTMP_MODULE); + +#else + + ngx_rtmp_max_module = 0; + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + + ngx_modules[m]->ctx_index = ngx_rtmp_max_module++; + } + +#endif + + + /* the rtmp main_conf context, it is the same in the all rtmp contexts */ + + ctx->main_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_rtmp_max_module); + if (ctx->main_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * the rtmp null srv_conf context, it is used to merge + * the server{}s' srv_conf's + */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * the rtmp null app_conf context, it is used to merge + * the server{}s' app_conf's + */ + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * create the main_conf's, the null srv_conf's, and the null app_conf's + * of the all rtmp modules + */ + +#if (nginx_version >= 1009011) + modules = cf->cycle->modules; +#else + modules = ngx_modules; +#endif + + for (m = 0; modules[m]; m++) { + if (modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[m]->ctx; + mi = modules[m]->ctx_index; + + if (module->create_main_conf) { + ctx->main_conf[mi] = module->create_main_conf(cf); + if (ctx->main_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + + if (module->create_srv_conf) { + ctx->srv_conf[mi] = module->create_srv_conf(cf); + if (ctx->srv_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + + if (module->create_app_conf) { + ctx->app_conf[mi] = module->create_app_conf(cf); + if (ctx->app_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + pcf = *cf; + cf->ctx = ctx; + + for (m = 0; modules[m]; m++) { + if (modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[m]->ctx; + + if (module->preconfiguration) { + if (module->preconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + + /* parse inside the rtmp{} block */ + + cf->module_type = NGX_RTMP_MODULE; + cf->cmd_type = NGX_RTMP_MAIN_CONF; + rv = ngx_conf_parse(cf, NULL); + + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + + + /* init rtmp{} main_conf's, merge the server{}s' srv_conf's */ + + cmcf = ctx->main_conf[ngx_rtmp_core_module.ctx_index]; + cscfp = cmcf->servers.elts; + + for (m = 0; modules[m]; m++) { + if (modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[m]->ctx; + mi = modules[m]->ctx_index; + + /* init rtmp{} main_conf's */ + + cf->ctx = ctx; + + if (module->init_main_conf) { + rv = module->init_main_conf(cf, ctx->main_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + + for (s = 0; s < cmcf->servers.nelts; s++) { + + /* merge the server{}s' srv_conf's */ + + cf->ctx = cscfp[s]->ctx; + + if (module->merge_srv_conf) { + rv = module->merge_srv_conf(cf, + ctx->srv_conf[mi], + cscfp[s]->ctx->srv_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + + if (module->merge_app_conf) { + + /* merge the server{}'s app_conf */ + + /*ctx->app_conf = cscfp[s]->ctx->loc_conf;*/ + + rv = module->merge_app_conf(cf, + ctx->app_conf[mi], + cscfp[s]->ctx->app_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + + /* merge the applications{}' app_conf's */ + + cscf = cscfp[s]->ctx->srv_conf[ngx_rtmp_core_module.ctx_index]; + + rv = ngx_rtmp_merge_applications(cf, &cscf->applications, + cscfp[s]->ctx->app_conf, + module, mi); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + + } + } + + + if (ngx_rtmp_init_events(cf, cmcf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + for (m = 0; modules[m]; m++) { + if (modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[m]->ctx; + + if (module->postconfiguration) { + if (module->postconfiguration(cf) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + + *cf = pcf; + + if (ngx_rtmp_init_event_handlers(cf, cmcf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&ports, cf->temp_pool, 4, sizeof(ngx_rtmp_conf_port_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + listen = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts; i++) { + if (ngx_rtmp_add_ports(cf, &ports, &listen[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + return ngx_rtmp_optimize_servers(cf, &ports); +} + + +static char * +ngx_rtmp_merge_applications(ngx_conf_t *cf, ngx_array_t *applications, + void **app_conf, ngx_rtmp_module_t *module, ngx_uint_t ctx_index) +{ + char *rv; + ngx_rtmp_conf_ctx_t *ctx, saved; + ngx_rtmp_core_app_conf_t **cacfp; + ngx_uint_t n; + ngx_rtmp_core_app_conf_t *cacf; + + if (applications == NULL) { + return NGX_CONF_OK; + } + + ctx = (ngx_rtmp_conf_ctx_t *) cf->ctx; + saved = *ctx; + + cacfp = applications->elts; + for (n = 0; n < applications->nelts; ++n, ++cacfp) { + + ctx->app_conf = (*cacfp)->app_conf; + + rv = module->merge_app_conf(cf, app_conf[ctx_index], + (*cacfp)->app_conf[ctx_index]); + if (rv != NGX_CONF_OK) { + return rv; + } + + cacf = (*cacfp)->app_conf[ngx_rtmp_core_module.ctx_index]; + rv = ngx_rtmp_merge_applications(cf, &cacf->applications, + (*cacfp)->app_conf, + module, ctx_index); + if (rv != NGX_CONF_OK) { + return rv; + } + } + + *ctx = saved; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_init_events(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf) +{ + size_t n; + + for(n = 0; n < NGX_RTMP_MAX_EVENT; ++n) { + if (ngx_array_init(&cmcf->events[n], cf->pool, 1, + sizeof(ngx_rtmp_handler_pt)) != NGX_OK) + { + return NGX_ERROR; + } + } + + if (ngx_array_init(&cmcf->amf, cf->pool, 1, + sizeof(ngx_rtmp_amf_handler_t)) != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_init_event_handlers(ngx_conf_t *cf, ngx_rtmp_core_main_conf_t *cmcf) +{ + ngx_hash_init_t calls_hash; + ngx_rtmp_handler_pt *eh; + ngx_rtmp_amf_handler_t *h; + ngx_hash_key_t *ha; + size_t n, m; + + static size_t pm_events[] = { + NGX_RTMP_MSG_CHUNK_SIZE, + NGX_RTMP_MSG_ABORT, + NGX_RTMP_MSG_ACK, + NGX_RTMP_MSG_ACK_SIZE, + NGX_RTMP_MSG_BANDWIDTH + }; + + static size_t amf_events[] = { + NGX_RTMP_MSG_AMF_CMD, + NGX_RTMP_MSG_AMF_META, + NGX_RTMP_MSG_AMF_SHARED, + NGX_RTMP_MSG_AMF3_CMD, + NGX_RTMP_MSG_AMF3_META, + NGX_RTMP_MSG_AMF3_SHARED + }; + + /* init standard protocol events */ + for(n = 0; n < sizeof(pm_events) / sizeof(pm_events[0]); ++n) { + eh = ngx_array_push(&cmcf->events[pm_events[n]]); + *eh = ngx_rtmp_protocol_message_handler; + } + + /* init amf events */ + for(n = 0; n < sizeof(amf_events) / sizeof(amf_events[0]); ++n) { + eh = ngx_array_push(&cmcf->events[amf_events[n]]); + *eh = ngx_rtmp_amf_message_handler; + } + + /* init user protocol events */ + eh = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_USER]); + *eh = ngx_rtmp_user_message_handler; + + /* aggregate to audio/video map */ + eh = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AGGREGATE]); + *eh = ngx_rtmp_aggregate_message_handler; + + /* init amf callbacks */ + ngx_array_init(&cmcf->amf_arrays, cf->pool, 1, sizeof(ngx_hash_key_t)); + + h = cmcf->amf.elts; + for(n = 0; n < cmcf->amf.nelts; ++n, ++h) { + ha = cmcf->amf_arrays.elts; + for(m = 0; m < cmcf->amf_arrays.nelts; ++m, ++ha) { + if (h->name.len == ha->key.len + && !ngx_strncmp(h->name.data, ha->key.data, ha->key.len)) + { + break; + } + } + if (m == cmcf->amf_arrays.nelts) { + ha = ngx_array_push(&cmcf->amf_arrays); + ha->key = h->name; + ha->key_hash = ngx_hash_key_lc(ha->key.data, ha->key.len); + ha->value = ngx_array_create(cf->pool, 1, + sizeof(ngx_rtmp_handler_pt)); + if (ha->value == NULL) { + return NGX_ERROR; + } + } + + eh = ngx_array_push((ngx_array_t*)ha->value); + *eh = h->handler; + } + + calls_hash.hash = &cmcf->amf_hash; + calls_hash.key = ngx_hash_key_lc; + calls_hash.max_size = 512; + calls_hash.bucket_size = ngx_cacheline_size; + calls_hash.name = "amf_hash"; + calls_hash.pool = cf->pool; + calls_hash.temp_pool = NULL; + + if (ngx_hash_init(&calls_hash, cmcf->amf_arrays.elts, cmcf->amf_arrays.nelts) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_add_ports(ngx_conf_t *cf, ngx_array_t *ports, + ngx_rtmp_listen_t *listen) +{ + in_port_t p; + ngx_uint_t i; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_rtmp_conf_port_t *port; + ngx_rtmp_conf_addr_t *addr; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + sa = (struct sockaddr *) &listen->sockaddr; + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + p = sin6->sin6_port; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + p = sin->sin_port; + break; + } + + port = ports->elts; + for (i = 0; i < ports->nelts; i++) { + if (p == port[i].port && sa->sa_family == port[i].family) { + + /* a port is already in the port list */ + + port = &port[i]; + goto found; + } + } + + /* add a port to the port list */ + + port = ngx_array_push(ports); + if (port == NULL) { + return NGX_ERROR; + } + + port->family = sa->sa_family; + port->port = p; + + if (ngx_array_init(&port->addrs, cf->temp_pool, 2, + sizeof(ngx_rtmp_conf_addr_t)) + != NGX_OK) + { + return NGX_ERROR; + } + +found: + + addr = ngx_array_push(&port->addrs); + if (addr == NULL) { + return NGX_ERROR; + } + + addr->sockaddr = (struct sockaddr *) &listen->sockaddr; + addr->socklen = listen->socklen; + addr->ctx = listen->ctx; + addr->bind = listen->bind; + addr->wildcard = listen->wildcard; + addr->so_keepalive = listen->so_keepalive; + addr->proxy_protocol = listen->proxy_protocol; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + addr->tcp_keepidle = listen->tcp_keepidle; + addr->tcp_keepintvl = listen->tcp_keepintvl; + addr->tcp_keepcnt = listen->tcp_keepcnt; +#endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + addr->ipv6only = listen->ipv6only; +#endif + + return NGX_OK; +} + + +static char * +ngx_rtmp_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) +{ + ngx_uint_t i, p, last, bind_wildcard; + ngx_listening_t *ls; + ngx_rtmp_port_t *mport; + ngx_rtmp_conf_port_t *port; + ngx_rtmp_conf_addr_t *addr; + + port = ports->elts; + for (p = 0; p < ports->nelts; p++) { + + ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, + sizeof(ngx_rtmp_conf_addr_t), ngx_rtmp_cmp_conf_addrs); + + addr = port[p].addrs.elts; + last = port[p].addrs.nelts; + + /* + * if there is the binding to the "*:port" then we need to bind() + * to the "*:port" only and ignore the other bindings + */ + + if (addr[last - 1].wildcard) { + addr[last - 1].bind = 1; + bind_wildcard = 1; + + } else { + bind_wildcard = 0; + } + + i = 0; + + while (i < last) { + + if (bind_wildcard && !addr[i].bind) { + i++; + continue; + } + + ls = ngx_create_listening(cf, addr[i].sockaddr, addr[i].socklen); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ls->addr_ntop = 1; + ls->handler = ngx_rtmp_init_connection; + ls->pool_size = 4096; + + /* TODO: error_log directive */ + ls->logp = &cf->cycle->new_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; + + ls->keepalive = addr[i].so_keepalive; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + ls->keepidle = addr[i].tcp_keepidle; + ls->keepintvl = addr[i].tcp_keepintvl; + ls->keepcnt = addr[i].tcp_keepcnt; +#endif + +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + ls->ipv6only = addr[i].ipv6only; +#endif + + mport = ngx_palloc(cf->pool, sizeof(ngx_rtmp_port_t)); + if (mport == NULL) { + return NGX_CONF_ERROR; + } + + ls->servers = mport; + + if (i == last - 1) { + mport->naddrs = last; + + } else { + mport->naddrs = 1; + i = 0; + } + + switch (ls->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + if (ngx_rtmp_add_addrs6(cf, mport, addr) != NGX_OK) { + return NGX_CONF_ERROR; + } + break; +#endif + default: /* AF_INET */ + if (ngx_rtmp_add_addrs(cf, mport, addr) != NGX_OK) { + return NGX_CONF_ERROR; + } + break; + } + + addr++; + last--; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_add_addrs(ngx_conf_t *cf, ngx_rtmp_port_t *mport, + ngx_rtmp_conf_addr_t *addr) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_rtmp_in_addr_t *addrs; + struct sockaddr_in *sin; + u_char buf[NGX_SOCKADDR_STRLEN]; + + mport->addrs = ngx_pcalloc(cf->pool, + mport->naddrs * sizeof(ngx_rtmp_in_addr_t)); + if (mport->addrs == NULL) { + return NGX_ERROR; + } + + addrs = mport->addrs; + + for (i = 0; i < mport->naddrs; i++) { + + sin = (struct sockaddr_in *) addr[i].sockaddr; + addrs[i].addr = sin->sin_addr.s_addr; + + addrs[i].conf.ctx = addr[i].ctx; + + len = ngx_sock_ntop(addr[i].sockaddr, +#if (nginx_version >= 1005003) + addr[i].socklen, +#endif + buf, NGX_SOCKADDR_STRLEN, 1); + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, buf, len); + + addrs[i].conf.addr_text.len = len; + addrs[i].conf.addr_text.data = p; + addrs[i].conf.proxy_protocol = addr->proxy_protocol; + } + + return NGX_OK; +} + + +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_rtmp_add_addrs6(ngx_conf_t *cf, ngx_rtmp_port_t *mport, + ngx_rtmp_conf_addr_t *addr) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_rtmp_in6_addr_t *addrs6; + struct sockaddr_in6 *sin6; + u_char buf[NGX_SOCKADDR_STRLEN]; + + mport->addrs = ngx_pcalloc(cf->pool, + mport->naddrs * sizeof(ngx_rtmp_in6_addr_t)); + if (mport->addrs == NULL) { + return NGX_ERROR; + } + + addrs6 = mport->addrs; + + for (i = 0; i < mport->naddrs; i++) { + + sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + addrs6[i].addr6 = sin6->sin6_addr; + + addrs6[i].conf.ctx = addr[i].ctx; + + len = ngx_sock_ntop(addr[i].sockaddr, +#if (nginx_version >= 1005003) + addr[i].socklen, +#endif + buf, NGX_SOCKADDR_STRLEN, 1); + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, buf, len); + + addrs6[i].conf.addr_text.len = len; + addrs6[i].conf.addr_text.data = p; + addrs6[i].conf.proxy_protocol = addr->proxy_protocol; + } + + return NGX_OK; +} + +#endif + + +static ngx_int_t +ngx_rtmp_cmp_conf_addrs(const void *one, const void *two) +{ + ngx_rtmp_conf_addr_t *first, *second; + + first = (ngx_rtmp_conf_addr_t *) one; + second = (ngx_rtmp_conf_addr_t *) two; + + if (first->wildcard) { + /* a wildcard must be the last resort, shift it to the end */ + return 1; + } + + if (first->bind && !second->bind) { + /* shift explicit bind()ed addresses to the start */ + return -1; + } + + if (!first->bind && second->bind) { + /* shift explicit bind()ed addresses to the start */ + return 1; + } + + /* do not sort by default */ + + return 0; +} + + +ngx_int_t +ngx_rtmp_fire_event(ngx_rtmp_session_t *s, ngx_uint_t evt, + ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_array_t *ch; + ngx_rtmp_handler_pt *hh; + size_t n; + + cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); + + ch = &cmcf->events[evt]; + hh = ch->elts; + for(n = 0; n < ch->nelts; ++n, ++hh) { + if (*hh && (*hh)(s, h, in) != NGX_OK) { + return NGX_ERROR; + } + } + return NGX_OK; +} + + +void * +ngx_rtmp_rmemcpy(void *dst, const void* src, size_t n) +{ + u_char *d, *s; + + d = dst; + s = (u_char*)src + n - 1; + + while(s >= (u_char*)src) { + *d++ = *s--; + } + + return dst; +} + + +static ngx_int_t +ngx_rtmp_init_process(ngx_cycle_t *cycle) +{ +#if (nginx_version >= 1007005) + ngx_queue_init(&ngx_rtmp_init_queue); +#endif + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp.h b/debian/modules/nginx-rtmp/ngx_rtmp.h new file mode 100644 index 0000000..e6c34d9 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp.h @@ -0,0 +1,622 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_H_INCLUDED_ +#define _NGX_RTMP_H_INCLUDED_ + + +#include +#include +#include +#include +#include + +#include "ngx_rtmp_amf.h" +#include "ngx_rtmp_bandwidth.h" + + +#if (NGX_WIN32) +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +#endif + + +typedef struct { + void **main_conf; + void **srv_conf; + void **app_conf; +} ngx_rtmp_conf_ctx_t; + + +typedef struct { + u_char sockaddr[NGX_SOCKADDRLEN]; + socklen_t socklen; + + /* server ctx */ + ngx_rtmp_conf_ctx_t *ctx; + + unsigned bind:1; + unsigned wildcard:1; +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif + unsigned so_keepalive:2; + unsigned proxy_protocol:1; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; +#endif +} ngx_rtmp_listen_t; + + +typedef struct { + ngx_rtmp_conf_ctx_t *ctx; + ngx_str_t addr_text; + unsigned proxy_protocol:1; +} ngx_rtmp_addr_conf_t; + +typedef struct { + in_addr_t addr; + ngx_rtmp_addr_conf_t conf; +} ngx_rtmp_in_addr_t; + + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr6; + ngx_rtmp_addr_conf_t conf; +} ngx_rtmp_in6_addr_t; + +#endif + + +typedef struct { + void *addrs; + ngx_uint_t naddrs; +} ngx_rtmp_port_t; + + +typedef struct { + int family; + in_port_t port; + ngx_array_t addrs; /* array of ngx_rtmp_conf_addr_t */ +} ngx_rtmp_conf_port_t; + + +typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_rtmp_conf_ctx_t *ctx; + + unsigned bind:1; + unsigned wildcard:1; +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif + unsigned so_keepalive:2; + unsigned proxy_protocol:1; +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + int tcp_keepidle; + int tcp_keepintvl; + int tcp_keepcnt; +#endif +} ngx_rtmp_conf_addr_t; + + +#define NGX_RTMP_VERSION 3 + +#define NGX_LOG_DEBUG_RTMP NGX_LOG_DEBUG_CORE + +#define NGX_RTMP_DEFAULT_CHUNK_SIZE 128 + + +/* RTMP message types */ +#define NGX_RTMP_MSG_CHUNK_SIZE 1 +#define NGX_RTMP_MSG_ABORT 2 +#define NGX_RTMP_MSG_ACK 3 +#define NGX_RTMP_MSG_USER 4 +#define NGX_RTMP_MSG_ACK_SIZE 5 +#define NGX_RTMP_MSG_BANDWIDTH 6 +#define NGX_RTMP_MSG_EDGE 7 +#define NGX_RTMP_MSG_AUDIO 8 +#define NGX_RTMP_MSG_VIDEO 9 +#define NGX_RTMP_MSG_AMF3_META 15 +#define NGX_RTMP_MSG_AMF3_SHARED 16 +#define NGX_RTMP_MSG_AMF3_CMD 17 +#define NGX_RTMP_MSG_AMF_META 18 +#define NGX_RTMP_MSG_AMF_SHARED 19 +#define NGX_RTMP_MSG_AMF_CMD 20 +#define NGX_RTMP_MSG_AGGREGATE 22 +#define NGX_RTMP_MSG_MAX 22 + +#define NGX_RTMP_CONNECT NGX_RTMP_MSG_MAX + 1 +#define NGX_RTMP_DISCONNECT NGX_RTMP_MSG_MAX + 2 +#define NGX_RTMP_HANDSHAKE_DONE NGX_RTMP_MSG_MAX + 3 +#define NGX_RTMP_MAX_EVENT NGX_RTMP_MSG_MAX + 4 + + +/* RMTP control message types */ +#define NGX_RTMP_USER_STREAM_BEGIN 0 +#define NGX_RTMP_USER_STREAM_EOF 1 +#define NGX_RTMP_USER_STREAM_DRY 2 +#define NGX_RTMP_USER_SET_BUFLEN 3 +#define NGX_RTMP_USER_RECORDED 4 +#define NGX_RTMP_USER_PING_REQUEST 6 +#define NGX_RTMP_USER_PING_RESPONSE 7 +#define NGX_RTMP_USER_UNKNOWN 8 +#define NGX_RTMP_USER_BUFFER_END 31 + + +/* Chunk header: + * max 3 basic header + * + max 11 message header + * + max 4 extended header (timestamp) */ +#define NGX_RTMP_MAX_CHUNK_HEADER 18 + + +typedef struct { + uint32_t csid; /* chunk stream id */ + uint32_t timestamp; /* timestamp (delta) */ + uint32_t mlen; /* message length */ + uint8_t type; /* message type id */ + uint32_t msid; /* message stream id */ +} ngx_rtmp_header_t; + + +typedef struct { + ngx_rtmp_header_t hdr; + uint32_t dtime; + uint32_t len; /* current fragment length */ + uint8_t ext; + ngx_chain_t *in; +} ngx_rtmp_stream_t; + + +/* disable zero-sized array warning by msvc */ + +#if (NGX_WIN32) +#pragma warning(push) +#pragma warning(disable:4200) +#endif + + +typedef struct { + uint32_t signature; /* "RTMP" */ /* <-- FIXME wtf */ + + ngx_event_t close; + + void **ctx; + void **main_conf; + void **srv_conf; + void **app_conf; + + ngx_str_t *addr_text; + int connected; + +#if (nginx_version >= 1007005) + ngx_queue_t posted_dry_events; +#else + ngx_event_t *posted_dry_events; +#endif + + /* client buffer time in msec */ + uint32_t buflen; + uint32_t ack_size; + + /* connection parameters */ + ngx_str_t app; + ngx_str_t args; + ngx_str_t flashver; + ngx_str_t swf_url; + ngx_str_t tc_url; + uint32_t acodecs; + uint32_t vcodecs; + ngx_str_t page_url; + + /* handshake data */ + ngx_buf_t *hs_buf; + u_char *hs_digest; + unsigned hs_old:1; + ngx_uint_t hs_stage; + + /* connection timestamps */ + ngx_msec_t epoch; + ngx_msec_t peer_epoch; + ngx_msec_t base_time; + uint32_t current_time; + + /* ping */ + ngx_event_t ping_evt; + unsigned ping_active:1; + unsigned ping_reset:1; + + /* auto-pushed? */ + unsigned auto_pushed:1; + unsigned relay:1; + unsigned static_relay:1; + + /* input stream 0 (reserved by RTMP spec) + * is used as free chain link */ + + ngx_rtmp_stream_t *in_streams; + uint32_t in_csid; + ngx_uint_t in_chunk_size; + ngx_pool_t *in_pool; + uint32_t in_bytes; + uint32_t in_last_ack; + + ngx_pool_t *in_old_pool; + ngx_int_t in_chunk_size_changing; + + ngx_connection_t *connection; + + /* circular buffer of RTMP message pointers */ + ngx_msec_t timeout; + uint32_t out_bytes; + size_t out_pos, out_last; + ngx_chain_t *out_chain; + u_char *out_bpos; + unsigned out_buffer:1; + size_t out_queue; + size_t out_cork; + ngx_chain_t *out[0]; +} ngx_rtmp_session_t; + + +#if (NGX_WIN32) +#pragma warning(pop) +#endif + + +/* handler result code: + * NGX_ERROR - error + * NGX_OK - success, may continue + * NGX_DONE - success, input parsed, reply sent; need no + * more calls on this event */ +typedef ngx_int_t (*ngx_rtmp_handler_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); + + +typedef struct { + ngx_str_t name; + ngx_rtmp_handler_pt handler; +} ngx_rtmp_amf_handler_t; + + +typedef struct { + ngx_array_t servers; /* ngx_rtmp_core_srv_conf_t */ + ngx_array_t listen; /* ngx_rtmp_listen_t */ + + ngx_array_t events[NGX_RTMP_MAX_EVENT]; + + ngx_hash_t amf_hash; + ngx_array_t amf_arrays; + ngx_array_t amf; +} ngx_rtmp_core_main_conf_t; + + +/* global main conf for stats */ +extern ngx_rtmp_core_main_conf_t *ngx_rtmp_core_main_conf; + + +typedef struct ngx_rtmp_core_srv_conf_s { + ngx_array_t applications; /* ngx_rtmp_core_app_conf_t */ + + ngx_msec_t timeout; + ngx_msec_t ping; + ngx_msec_t ping_timeout; + ngx_flag_t so_keepalive; + ngx_int_t max_streams; + + ngx_uint_t ack_window; + + ngx_int_t chunk_size; + ngx_pool_t *pool; + ngx_chain_t *free; + ngx_chain_t *free_hs; + size_t max_message; + ngx_flag_t play_time_fix; + ngx_flag_t publish_time_fix; + ngx_flag_t busy; + size_t out_queue; + size_t out_cork; + ngx_msec_t buflen; + + ngx_rtmp_conf_ctx_t *ctx; +} ngx_rtmp_core_srv_conf_t; + + +typedef struct { + ngx_array_t applications; /* ngx_rtmp_core_app_conf_t */ + ngx_str_t name; + void **app_conf; +} ngx_rtmp_core_app_conf_t; + + +typedef struct { + ngx_str_t *client; + ngx_rtmp_session_t *session; +} ngx_rtmp_error_log_ctx_t; + + +typedef struct { + ngx_int_t (*preconfiguration)(ngx_conf_t *cf); + ngx_int_t (*postconfiguration)(ngx_conf_t *cf); + + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, + void *conf); + + void *(*create_app_conf)(ngx_conf_t *cf); + char *(*merge_app_conf)(ngx_conf_t *cf, void *prev, + void *conf); +} ngx_rtmp_module_t; + +#define NGX_RTMP_MODULE 0x504D5452 /* "RTMP" */ + +#define NGX_RTMP_MAIN_CONF 0x02000000 +#define NGX_RTMP_SRV_CONF 0x04000000 +#define NGX_RTMP_APP_CONF 0x08000000 +#define NGX_RTMP_REC_CONF 0x10000000 + + +#define NGX_RTMP_MAIN_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, main_conf) +#define NGX_RTMP_SRV_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, srv_conf) +#define NGX_RTMP_APP_CONF_OFFSET offsetof(ngx_rtmp_conf_ctx_t, app_conf) + + +#define ngx_rtmp_get_module_ctx(s, module) (s)->ctx[module.ctx_index] +#define ngx_rtmp_set_ctx(s, c, module) s->ctx[module.ctx_index] = c; +#define ngx_rtmp_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL; + + +#define ngx_rtmp_get_module_main_conf(s, module) \ + (s)->main_conf[module.ctx_index] +#define ngx_rtmp_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index] +#define ngx_rtmp_get_module_app_conf(s, module) ((s)->app_conf ? \ + (s)->app_conf[module.ctx_index] : NULL) + +#define ngx_rtmp_conf_get_module_main_conf(cf, module) \ + ((ngx_rtmp_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] +#define ngx_rtmp_conf_get_module_srv_conf(cf, module) \ + ((ngx_rtmp_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] +#define ngx_rtmp_conf_get_module_app_conf(cf, module) \ + ((ngx_rtmp_conf_ctx_t *) cf->ctx)->app_conf[module.ctx_index] + + +#ifdef NGX_DEBUG +char* ngx_rtmp_message_type(uint8_t type); +char* ngx_rtmp_user_message_type(uint16_t evt); +#endif + +void ngx_rtmp_init_connection(ngx_connection_t *c); +ngx_rtmp_session_t * ngx_rtmp_init_session(ngx_connection_t *c, + ngx_rtmp_addr_conf_t *addr_conf); +void ngx_rtmp_finalize_session(ngx_rtmp_session_t *s); +void ngx_rtmp_handshake(ngx_rtmp_session_t *s); +void ngx_rtmp_client_handshake(ngx_rtmp_session_t *s, unsigned async); +void ngx_rtmp_free_handshake_buffers(ngx_rtmp_session_t *s); +void ngx_rtmp_cycle(ngx_rtmp_session_t *s); +void ngx_rtmp_reset_ping(ngx_rtmp_session_t *s); +ngx_int_t ngx_rtmp_fire_event(ngx_rtmp_session_t *s, ngx_uint_t evt, + ngx_rtmp_header_t *h, ngx_chain_t *in); + + +ngx_int_t ngx_rtmp_set_chunk_size(ngx_rtmp_session_t *s, ngx_uint_t size); + + +/* Bit reverse: we need big-endians in many places */ +void * ngx_rtmp_rmemcpy(void *dst, const void* src, size_t n); + +#define ngx_rtmp_rcpymem(dst, src, n) \ + (((u_char*)ngx_rtmp_rmemcpy(dst, src, n)) + (n)) + + +static ngx_inline uint16_t +ngx_rtmp_r16(uint16_t n) +{ + return (n << 8) | (n >> 8); +} + + +static ngx_inline uint32_t +ngx_rtmp_r32(uint32_t n) +{ + return (n << 24) | ((n << 8) & 0xff0000) | ((n >> 8) & 0xff00) | (n >> 24); +} + + +static ngx_inline uint64_t +ngx_rtmp_r64(uint64_t n) +{ + return (uint64_t) ngx_rtmp_r32((uint32_t) n) << 32 | + ngx_rtmp_r32((uint32_t) (n >> 32)); +} + + +/* Receiving messages */ +ngx_int_t ngx_rtmp_receive_message(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +ngx_int_t ngx_rtmp_protocol_message_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +ngx_int_t ngx_rtmp_user_message_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +ngx_int_t ngx_rtmp_aggregate_message_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +ngx_int_t ngx_rtmp_amf_message_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +ngx_int_t ngx_rtmp_amf_shared_object_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); + + +/* Shared output buffers */ + +/* Store refcount in negative bytes of shared buffer */ + +#define NGX_RTMP_REFCOUNT_TYPE uint32_t +#define NGX_RTMP_REFCOUNT_BYTES sizeof(NGX_RTMP_REFCOUNT_TYPE) + +#define ngx_rtmp_ref(b) \ + *((NGX_RTMP_REFCOUNT_TYPE*)(b) - 1) + +#define ngx_rtmp_ref_set(b, v) \ + ngx_rtmp_ref(b) = v + +#define ngx_rtmp_ref_get(b) \ + ++ngx_rtmp_ref(b) + +#define ngx_rtmp_ref_put(b) \ + --ngx_rtmp_ref(b) + +ngx_chain_t * ngx_rtmp_alloc_shared_buf(ngx_rtmp_core_srv_conf_t *cscf); +void ngx_rtmp_free_shared_chain(ngx_rtmp_core_srv_conf_t *cscf, + ngx_chain_t *in); +ngx_chain_t * ngx_rtmp_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf, + ngx_chain_t *head, ngx_chain_t *in); + +#define ngx_rtmp_acquire_shared_chain(in) \ + ngx_rtmp_ref_get(in); \ + + +/* Sending messages */ +void ngx_rtmp_prepare_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_rtmp_header_t *lh, ngx_chain_t *out); +ngx_int_t ngx_rtmp_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out, + ngx_uint_t priority); + +/* Note on priorities: + * the bigger value the lower the priority. + * priority=0 is the highest */ + + +#define NGX_RTMP_LIMIT_SOFT 0 +#define NGX_RTMP_LIMIT_HARD 1 +#define NGX_RTMP_LIMIT_DYNAMIC 2 + +/* Protocol control messages */ +ngx_chain_t * ngx_rtmp_create_chunk_size(ngx_rtmp_session_t *s, + uint32_t chunk_size); +ngx_chain_t * ngx_rtmp_create_abort(ngx_rtmp_session_t *s, + uint32_t csid); +ngx_chain_t * ngx_rtmp_create_ack(ngx_rtmp_session_t *s, + uint32_t seq); +ngx_chain_t * ngx_rtmp_create_ack_size(ngx_rtmp_session_t *s, + uint32_t ack_size); +ngx_chain_t * ngx_rtmp_create_bandwidth(ngx_rtmp_session_t *s, + uint32_t ack_size, uint8_t limit_type); + +ngx_int_t ngx_rtmp_send_chunk_size(ngx_rtmp_session_t *s, + uint32_t chunk_size); +ngx_int_t ngx_rtmp_send_abort(ngx_rtmp_session_t *s, + uint32_t csid); +ngx_int_t ngx_rtmp_send_ack(ngx_rtmp_session_t *s, + uint32_t seq); +ngx_int_t ngx_rtmp_send_ack_size(ngx_rtmp_session_t *s, + uint32_t ack_size); +ngx_int_t ngx_rtmp_send_bandwidth(ngx_rtmp_session_t *s, + uint32_t ack_size, uint8_t limit_type); + +/* User control messages */ +ngx_chain_t * ngx_rtmp_create_stream_begin(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_chain_t * ngx_rtmp_create_stream_eof(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_chain_t * ngx_rtmp_create_stream_dry(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_chain_t * ngx_rtmp_create_set_buflen(ngx_rtmp_session_t *s, + uint32_t msid, uint32_t buflen_msec); +ngx_chain_t * ngx_rtmp_create_recorded(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_chain_t * ngx_rtmp_create_ping_request(ngx_rtmp_session_t *s, + uint32_t timestamp); +ngx_chain_t * ngx_rtmp_create_ping_response(ngx_rtmp_session_t *s, + uint32_t timestamp); + +ngx_int_t ngx_rtmp_send_stream_begin(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_int_t ngx_rtmp_send_stream_eof(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_int_t ngx_rtmp_send_stream_dry(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_int_t ngx_rtmp_send_set_buflen(ngx_rtmp_session_t *s, + uint32_t msid, uint32_t buflen_msec); +ngx_int_t ngx_rtmp_send_recorded(ngx_rtmp_session_t *s, + uint32_t msid); +ngx_int_t ngx_rtmp_send_ping_request(ngx_rtmp_session_t *s, + uint32_t timestamp); +ngx_int_t ngx_rtmp_send_ping_response(ngx_rtmp_session_t *s, + uint32_t timestamp); + +/* AMF sender/receiver */ +ngx_int_t ngx_rtmp_append_amf(ngx_rtmp_session_t *s, + ngx_chain_t **first, ngx_chain_t **last, + ngx_rtmp_amf_elt_t *elts, size_t nelts); +ngx_int_t ngx_rtmp_receive_amf(ngx_rtmp_session_t *s, ngx_chain_t *in, + ngx_rtmp_amf_elt_t *elts, size_t nelts); + +ngx_chain_t * ngx_rtmp_create_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_rtmp_amf_elt_t *elts, size_t nelts); +ngx_int_t ngx_rtmp_send_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_rtmp_amf_elt_t *elts, size_t nelts); + +/* AMF status sender */ +ngx_chain_t * ngx_rtmp_create_status(ngx_rtmp_session_t *s, char *code, + char* level, char *desc); +ngx_chain_t * ngx_rtmp_create_play_status(ngx_rtmp_session_t *s, char *code, + char* level, ngx_uint_t duration, ngx_uint_t bytes); +ngx_chain_t * ngx_rtmp_create_sample_access(ngx_rtmp_session_t *s); + +ngx_int_t ngx_rtmp_send_status(ngx_rtmp_session_t *s, char *code, + char* level, char *desc); +ngx_int_t ngx_rtmp_send_play_status(ngx_rtmp_session_t *s, char *code, + char* level, ngx_uint_t duration, ngx_uint_t bytes); +ngx_int_t ngx_rtmp_send_sample_access(ngx_rtmp_session_t *s); + + +/* Frame types */ +#define NGX_RTMP_VIDEO_KEY_FRAME 1 +#define NGX_RTMP_VIDEO_INTER_FRAME 2 +#define NGX_RTMP_VIDEO_DISPOSABLE_FRAME 3 + + +static ngx_inline ngx_int_t +ngx_rtmp_get_video_frame_type(ngx_chain_t *in) +{ + return (in->buf->pos[0] & 0xf0) >> 4; +} + + +static ngx_inline ngx_int_t +ngx_rtmp_is_codec_header(ngx_chain_t *in) +{ + return in->buf->pos + 1 < in->buf->last && in->buf->pos[1] == 0; +} + + +extern ngx_rtmp_bandwidth_t ngx_rtmp_bw_out; +extern ngx_rtmp_bandwidth_t ngx_rtmp_bw_in; + + +extern ngx_uint_t ngx_rtmp_naccepted; +#if (nginx_version >= 1007011) +extern ngx_queue_t ngx_rtmp_init_queue; +#elif (nginx_version >= 1007005) +extern ngx_thread_volatile ngx_queue_t ngx_rtmp_init_queue; +#else +extern ngx_thread_volatile ngx_event_t *ngx_rtmp_init_queue; +#endif + +extern ngx_uint_t ngx_rtmp_max_module; +extern ngx_module_t ngx_rtmp_core_module; + + +#endif /* _NGX_RTMP_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_access_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_access_module.c new file mode 100644 index 0000000..06d3bc2 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_access_module.c @@ -0,0 +1,471 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_play_pt next_play; + + +#define NGX_RTMP_ACCESS_PUBLISH 0x01 +#define NGX_RTMP_ACCESS_PLAY 0x02 + + +static char * ngx_rtmp_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_rtmp_access_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_access_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_access_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); + + +typedef struct { + in_addr_t mask; + in_addr_t addr; + ngx_uint_t deny; + ngx_uint_t flags; +} ngx_rtmp_access_rule_t; + + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr; + struct in6_addr mask; + ngx_uint_t deny; + ngx_uint_t flags; +} ngx_rtmp_access_rule6_t; + +#endif + + +typedef struct { + ngx_array_t rules; /* array of ngx_rtmp_access_rule_t */ +#if (NGX_HAVE_INET6) + ngx_array_t rules6; /* array of ngx_rtmp_access_rule6_t */ +#endif +} ngx_rtmp_access_app_conf_t; + + +static ngx_command_t ngx_rtmp_access_commands[] = { + + { ngx_string("allow"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12, + ngx_rtmp_access_rule, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("deny"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12, + ngx_rtmp_access_rule, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_access_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_access_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_access_create_app_conf, /* create app configuration */ + ngx_rtmp_access_merge_app_conf, /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_access_module = { + NGX_MODULE_V1, + &ngx_rtmp_access_module_ctx, /* module context */ + ngx_rtmp_access_commands, /* module directives */ + NGX_RTMP_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_rtmp_access_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_access_app_conf_t *aacf; + + aacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_access_app_conf_t)); + if (aacf == NULL) { + return NULL; + } + + if (ngx_array_init(&aacf->rules, cf->pool, 1, + sizeof(ngx_rtmp_access_rule_t)) + != NGX_OK) + { + return NULL; + } + +#if (NGX_HAVE_INET6) + if (ngx_array_init(&aacf->rules6, cf->pool, 1, + sizeof(ngx_rtmp_access_rule6_t)) + != NGX_OK) + { + return NULL; + } +#endif + + return aacf; +} + + +static ngx_int_t +ngx_rtmp_access_merge_rules(ngx_array_t *prev, ngx_array_t *rules) +{ + void *p; + + if (prev->nelts == 0) { + return NGX_OK; + } + + if (rules->nelts == 0) { + *rules = *prev; + return NGX_OK; + } + + p = ngx_array_push_n(rules, prev->nelts); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, prev->elts, prev->size * prev->nelts); + + return NGX_OK; +} + + +static char * +ngx_rtmp_access_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_access_app_conf_t *prev = parent; + ngx_rtmp_access_app_conf_t *conf = child; + + if (ngx_rtmp_access_merge_rules(&prev->rules, &conf->rules) != NGX_OK) { + return NGX_CONF_ERROR; + } + +#if (NGX_HAVE_INET6) + if (ngx_rtmp_access_merge_rules(&prev->rules6, &conf->rules6) != NGX_OK) { + return NGX_CONF_ERROR; + } +#endif + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_access_found(ngx_rtmp_session_t *s, ngx_uint_t deny) +{ + if (deny) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "access forbidden by rule"); + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_access_inet(ngx_rtmp_session_t *s, in_addr_t addr, ngx_uint_t flag) +{ + ngx_uint_t i; + ngx_rtmp_access_rule_t *rule; + ngx_rtmp_access_app_conf_t *ascf; + + ascf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_access_module); + + rule = ascf->rules.elts; + for (i = 0; i < ascf->rules.nelts; i++) { + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "access: %08XD %08XD %08XD", + addr, rule[i].mask, rule[i].addr); + + if ((addr & rule[i].mask) == rule[i].addr && (flag & rule[i].flags)) { + return ngx_rtmp_access_found(s, rule[i].deny); + } + } + + return NGX_OK; +} + + +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_rtmp_access_inet6(ngx_rtmp_session_t *s, u_char *p, ngx_uint_t flag) +{ + ngx_uint_t n; + ngx_uint_t i; + ngx_rtmp_access_rule6_t *rule6; + ngx_rtmp_access_app_conf_t *ascf; + + ascf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_access_module); + + rule6 = ascf->rules6.elts; + for (i = 0; i < ascf->rules6.nelts; i++) { + +#if (NGX_DEBUG) + { + size_t cl, ml, al; + u_char ct[NGX_INET6_ADDRSTRLEN]; + u_char mt[NGX_INET6_ADDRSTRLEN]; + u_char at[NGX_INET6_ADDRSTRLEN]; + + cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); + ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); + al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); + + ngx_log_debug6(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "access: %*s %*s %*s", cl, ct, ml, mt, al, at); + } +#endif + + for (n = 0; n < 16; n++) { + if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { + goto next; + } + } + + if (flag & rule6[i].flags) { + return ngx_rtmp_access_found(s, rule6[i].deny); + } + + next: + continue; + } + + return NGX_OK; +} + +#endif + + +static ngx_int_t +ngx_rtmp_access(ngx_rtmp_session_t *s, ngx_uint_t flag) +{ + struct sockaddr_in *sin; + ngx_rtmp_access_app_conf_t *ascf; +#if (NGX_HAVE_INET6) + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; +#endif + + ascf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_access_module); + if (ascf == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "access: NULL app conf"); + return NGX_ERROR; + } + + /* relay etc */ + if (s->connection->sockaddr == NULL) { + return NGX_OK; + } + + switch (s->connection->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) s->connection->sockaddr; + return ngx_rtmp_access_inet(s, sin->sin_addr.s_addr, flag); + +#if (NGX_HAVE_INET6) + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) s->connection->sockaddr; + p = sin6->sin6_addr.s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + return ngx_rtmp_access_inet(s, htonl(addr), flag); + } + + return ngx_rtmp_access_inet6(s, p, flag); + +#endif + } + + return NGX_OK; +} + + +static char * +ngx_rtmp_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_access_app_conf_t *ascf = conf; + + ngx_int_t rc; + ngx_uint_t all; + ngx_str_t *value; + ngx_cidr_t cidr; + ngx_rtmp_access_rule_t *rule; +#if (NGX_HAVE_INET6) + ngx_rtmp_access_rule6_t *rule6; +#endif + size_t n; + ngx_uint_t flags; + + ngx_memzero(&cidr, sizeof(ngx_cidr_t)); + + value = cf->args->elts; + + n = 1; + flags = 0; + + if (cf->args->nelts == 2) { + + flags = NGX_RTMP_ACCESS_PUBLISH | NGX_RTMP_ACCESS_PLAY; + + } else { + + for(; n < cf->args->nelts - 1; ++n) { + + if (value[n].len == sizeof("publish") - 1 && + ngx_strcmp(value[1].data, "publish") == 0) + { + flags |= NGX_RTMP_ACCESS_PUBLISH; + continue; + + } + + if (value[n].len == sizeof("play") - 1 && + ngx_strcmp(value[1].data, "play") == 0) + { + flags |= NGX_RTMP_ACCESS_PLAY; + continue; + + } + + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "unexpected access specified: '%V'", &value[n]); + return NGX_CONF_ERROR; + } + } + + all = (value[n].len == 3 && ngx_strcmp(value[n].data, "all") == 0); + + if (!all) { + + rc = ngx_ptocidr(&value[n], &cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + 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[1]); + } + } + + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + case 0: /* all */ + + rule6 = ngx_array_push(&ascf->rules6); + if (rule6 == NULL) { + return NGX_CONF_ERROR; + } + + rule6->mask = cidr.u.in6.mask; + rule6->addr = cidr.u.in6.addr; + rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; + rule6->flags = flags; + + if (!all) { + break; + } + + /* "all" passes through */ +#endif + + default: /* AF_INET */ + + rule = ngx_array_push(&ascf->rules); + if (rule == NULL) { + return NGX_CONF_ERROR; + } + + rule->mask = cidr.u.in.mask; + rule->addr = cidr.u.in.addr; + rule->deny = (value[0].data[0] == 'd') ? 1 : 0; + rule->flags = flags; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_access_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + if (s->auto_pushed) { + goto next; + } + + if (ngx_rtmp_access(s, NGX_RTMP_ACCESS_PUBLISH) != NGX_OK) { + return NGX_ERROR; + } + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_access_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + if (ngx_rtmp_access(s, NGX_RTMP_ACCESS_PLAY) != NGX_OK) { + return NGX_ERROR; + } + + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_access_postconfiguration(ngx_conf_t *cf) +{ + /* chain handlers */ + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_access_publish; + + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_access_play; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_amf.c b/debian/modules/nginx-rtmp/ngx_rtmp_amf.c new file mode 100644 index 0000000..f133d0e --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_amf.c @@ -0,0 +1,645 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_amf.h" +#include "ngx_rtmp.h" +#include + + +static ngx_inline void* +ngx_rtmp_amf_reverse_copy(void *dst, void* src, size_t len) +{ + size_t k; + + if (dst == NULL || src == NULL) { + return NULL; + } + + for(k = 0; k < len; ++k) { + ((u_char*)dst)[k] = ((u_char*)src)[len - 1 - k]; + } + + return dst; +} + +#define NGX_RTMP_AMF_DEBUG_SIZE 16 + +#ifdef NGX_DEBUG +static void +ngx_rtmp_amf_debug(const char* op, ngx_log_t *log, u_char *p, size_t n) +{ + u_char hstr[3 * NGX_RTMP_AMF_DEBUG_SIZE + 1]; + u_char str[NGX_RTMP_AMF_DEBUG_SIZE + 1]; + u_char *hp, *sp; + static u_char hex[] = "0123456789ABCDEF"; + size_t i; + + hp = hstr; + sp = str; + + for(i = 0; i < n && i < NGX_RTMP_AMF_DEBUG_SIZE; ++i) { + *hp++ = ' '; + if (p) { + *hp++ = hex[(*p & 0xf0) >> 4]; + *hp++ = hex[*p & 0x0f]; + *sp++ = (*p >= 0x20 && *p <= 0x7e) ? + *p : (u_char)'?'; + ++p; + } else { + *hp++ = 'X'; + *hp++ = 'X'; + *sp++ = '?'; + } + } + *hp = *sp = '\0'; + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, log, 0, + "AMF %s (%d)%s '%s'", op, n, hstr, str); +} +#endif + +static ngx_int_t +ngx_rtmp_amf_get(ngx_rtmp_amf_ctx_t *ctx, void *p, size_t n) +{ + size_t size; + ngx_chain_t *l; + size_t offset; + u_char *pos, *last; +#ifdef NGX_DEBUG + void *op = p; + size_t on = n; +#endif + + if (!n) + return NGX_OK; + + for(l = ctx->link, offset = ctx->offset; l; l = l->next, offset = 0) { + + pos = l->buf->pos + offset; + last = l->buf->last; + + if (last >= pos + n) { + if (p) { + p = ngx_cpymem(p, pos, n); + } + ctx->offset = offset + n; + ctx->link = l; + +#ifdef NGX_DEBUG + ngx_rtmp_amf_debug("read", ctx->log, (u_char*)op, on); +#endif + + return NGX_OK; + } + + size = last - pos; + + if (p) { + p = ngx_cpymem(p, pos, size); + } + + n -= size; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, ctx->log, 0, + "AMF read eof (%d)", n); + + return NGX_DONE; +} + + +static ngx_int_t +ngx_rtmp_amf_put(ngx_rtmp_amf_ctx_t *ctx, void *p, size_t n) +{ + ngx_buf_t *b; + size_t size; + ngx_chain_t *l, *ln; + +#ifdef NGX_DEBUG + ngx_rtmp_amf_debug("write", ctx->log, (u_char*)p, n); +#endif + + l = ctx->link; + + if (ctx->link && ctx->first == NULL) { + ctx->first = ctx->link; + } + + while(n) { + b = l ? l->buf : NULL; + + if (b == NULL || b->last == b->end) { + + ln = ctx->alloc(ctx->arg); + if (ln == NULL) { + return NGX_ERROR; + } + + if (ctx->first == NULL) { + ctx->first = ln; + } + + if (l) { + l->next = ln; + } + + l = ln; + ctx->link = l; + b = l->buf; + } + + size = b->end - b->last; + + if (size >= n) { + b->last = ngx_cpymem(b->last, p, n); + return NGX_OK; + } + + b->last = ngx_cpymem(b->last, p, size); + p = (u_char*)p + size; + n -= size; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_amf_read_object(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts, + size_t nelts) +{ + uint8_t type; + uint16_t len; + size_t n, namelen, maxlen; + ngx_int_t rc; + u_char buf[2]; + + maxlen = 0; + for(n = 0; n < nelts; ++n) { + namelen = elts[n].name.len; + if (namelen > maxlen) + maxlen = namelen; + } + + for( ;; ) { + +#if !(NGX_WIN32) + char name[maxlen]; +#else + char name[1024]; + if (maxlen > sizeof(name)) { + return NGX_ERROR; + } +#endif + /* read key */ + switch (ngx_rtmp_amf_get(ctx, buf, 2)) { + case NGX_DONE: + /* Envivio sends unfinalized arrays */ + return NGX_OK; + case NGX_OK: + break; + default: + return NGX_ERROR; + } + + ngx_rtmp_amf_reverse_copy(&len, buf, 2); + + if (!len) + break; + + if (len <= maxlen) { + rc = ngx_rtmp_amf_get(ctx, name, len); + + } else { + rc = ngx_rtmp_amf_get(ctx, name, maxlen); + if (rc != NGX_OK) + return NGX_ERROR; + rc = ngx_rtmp_amf_get(ctx, 0, len - maxlen); + } + + if (rc != NGX_OK) + return NGX_ERROR; + + /* TODO: if we require array to be sorted on name + * then we could be able to use binary search */ + for(n = 0; n < nelts + && (len != elts[n].name.len + || ngx_strncmp(name, elts[n].name.data, len)); + ++n); + + if (ngx_rtmp_amf_read(ctx, n < nelts ? &elts[n] : NULL, 1) != NGX_OK) + return NGX_ERROR; + } + + if (ngx_rtmp_amf_get(ctx, &type, 1) != NGX_OK + || type != NGX_RTMP_AMF_END) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_amf_read_array(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts, + size_t nelts) +{ + uint32_t len; + size_t n; + u_char buf[4]; + + /* read length */ + if (ngx_rtmp_amf_get(ctx, buf, 4) != NGX_OK) + return NGX_ERROR; + + ngx_rtmp_amf_reverse_copy(&len, buf, 4); + + for (n = 0; n < len; ++n) { + if (ngx_rtmp_amf_read(ctx, n < nelts ? &elts[n] : NULL, 1) != NGX_OK) + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_amf_read_variant(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts, + size_t nelts) +{ + uint8_t type; + ngx_int_t rc; + size_t n; + ngx_rtmp_amf_elt_t elt; + + rc = ngx_rtmp_amf_get(ctx, &type, 1); + if (rc != NGX_OK) { + return rc; + } + + ngx_memzero(&elt, sizeof(elt)); + for (n = 0; n < nelts; ++n, ++elts) { + if (type == elts->type) { + elt.data = elts->data; + elt.len = elts->len; + } + } + + elt.type = type | NGX_RTMP_AMF_TYPELESS; + + return ngx_rtmp_amf_read(ctx, &elt, 1); +} + + +static ngx_int_t +ngx_rtmp_amf_is_compatible_type(uint8_t t1, uint8_t t2) +{ + return t1 == t2 + || (t1 == NGX_RTMP_AMF_OBJECT && t2 == NGX_RTMP_AMF_MIXED_ARRAY) + || (t2 == NGX_RTMP_AMF_OBJECT && t1 == NGX_RTMP_AMF_MIXED_ARRAY); +} + + +ngx_int_t +ngx_rtmp_amf_read(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_amf_elt_t *elts, + size_t nelts) +{ + void *data; + ngx_int_t type; + uint8_t type8; + size_t n; + uint16_t len; + ngx_int_t rc; + u_char buf[8]; + uint32_t max_index; + + for(n = 0; n < nelts; ++n) { + + if (elts && elts->type & NGX_RTMP_AMF_TYPELESS) { + type = elts->type & ~NGX_RTMP_AMF_TYPELESS; + data = elts->data; + + } else { + switch (ngx_rtmp_amf_get(ctx, &type8, 1)) { + case NGX_DONE: + if (elts->type & NGX_RTMP_AMF_OPTIONAL) { + return NGX_OK; + } + case NGX_ERROR: + return NGX_ERROR; + } + type = type8; + data = (elts && + ngx_rtmp_amf_is_compatible_type( + (uint8_t) (elts->type & 0xff), (uint8_t) type)) + ? elts->data + : NULL; + + if (elts && (elts->type & NGX_RTMP_AMF_CONTEXT)) { + if (data) { + *(ngx_rtmp_amf_ctx_t *) data = *ctx; + } + data = NULL; + } + } + + switch (type) { + case NGX_RTMP_AMF_NUMBER: + if (ngx_rtmp_amf_get(ctx, buf, 8) != NGX_OK) { + return NGX_ERROR; + } + ngx_rtmp_amf_reverse_copy(data, buf, 8); + break; + + case NGX_RTMP_AMF_BOOLEAN: + if (ngx_rtmp_amf_get(ctx, data, 1) != NGX_OK) { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_STRING: + if (ngx_rtmp_amf_get(ctx, buf, 2) != NGX_OK) { + return NGX_ERROR; + } + ngx_rtmp_amf_reverse_copy(&len, buf, 2); + + if (data == NULL) { + rc = ngx_rtmp_amf_get(ctx, data, len); + + } else if (elts->len <= len) { + rc = ngx_rtmp_amf_get(ctx, data, elts->len - 1); + if (rc != NGX_OK) + return NGX_ERROR; + ((char*)data)[elts->len - 1] = 0; + rc = ngx_rtmp_amf_get(ctx, NULL, len - elts->len + 1); + + } else { + rc = ngx_rtmp_amf_get(ctx, data, len); + ((char*)data)[len] = 0; + } + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + break; + + case NGX_RTMP_AMF_NULL: + case NGX_RTMP_AMF_ARRAY_NULL: + break; + + case NGX_RTMP_AMF_MIXED_ARRAY: + if (ngx_rtmp_amf_get(ctx, &max_index, 4) != NGX_OK) { + return NGX_ERROR; + } + + case NGX_RTMP_AMF_OBJECT: + if (ngx_rtmp_amf_read_object(ctx, data, + data && elts ? elts->len / sizeof(ngx_rtmp_amf_elt_t) : 0 + ) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_ARRAY: + if (ngx_rtmp_amf_read_array(ctx, data, + data && elts ? elts->len / sizeof(ngx_rtmp_amf_elt_t) : 0 + ) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_VARIANT_: + if (ngx_rtmp_amf_read_variant(ctx, data, + data && elts ? elts->len / sizeof(ngx_rtmp_amf_elt_t) : 0 + ) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_INT8: + if (ngx_rtmp_amf_get(ctx, data, 1) != NGX_OK) { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_INT16: + if (ngx_rtmp_amf_get(ctx, buf, 2) != NGX_OK) { + return NGX_ERROR; + } + ngx_rtmp_amf_reverse_copy(data, buf, 2); + break; + + case NGX_RTMP_AMF_INT32: + if (ngx_rtmp_amf_get(ctx, buf, 4) != NGX_OK) { + return NGX_ERROR; + } + ngx_rtmp_amf_reverse_copy(data, buf, 4); + break; + + case NGX_RTMP_AMF_END: + return NGX_OK; + + default: + return NGX_ERROR; + } + + if (elts) { + ++elts; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_amf_write_object(ngx_rtmp_amf_ctx_t *ctx, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + uint16_t len; + size_t n; + u_char buf[2]; + + for(n = 0; n < nelts; ++n) { + + len = (uint16_t) elts[n].name.len; + + if (ngx_rtmp_amf_put(ctx, + ngx_rtmp_amf_reverse_copy(buf, + &len, 2), 2) != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_rtmp_amf_put(ctx, elts[n].name.data, len) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_amf_write(ctx, &elts[n], 1) != NGX_OK) { + return NGX_ERROR; + } + } + + if (ngx_rtmp_amf_put(ctx, "\0\0", 2) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_amf_write_array(ngx_rtmp_amf_ctx_t *ctx, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + uint32_t len; + size_t n; + u_char buf[4]; + + len = nelts; + if (ngx_rtmp_amf_put(ctx, + ngx_rtmp_amf_reverse_copy(buf, + &len, 4), 4) != NGX_OK) + { + return NGX_ERROR; + } + + for(n = 0; n < nelts; ++n) { + if (ngx_rtmp_amf_write(ctx, &elts[n], 1) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_amf_write(ngx_rtmp_amf_ctx_t *ctx, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + size_t n; + ngx_int_t type; + uint8_t type8; + void *data; + uint16_t len; + uint32_t max_index; + u_char buf[8]; + + for(n = 0; n < nelts; ++n) { + + type = elts[n].type; + data = elts[n].data; + len = (uint16_t) elts[n].len; + + if (type & NGX_RTMP_AMF_TYPELESS) { + type &= ~NGX_RTMP_AMF_TYPELESS; + } else { + type8 = (uint8_t)type; + if (ngx_rtmp_amf_put(ctx, &type8, 1) != NGX_OK) + return NGX_ERROR; + } + + switch(type) { + case NGX_RTMP_AMF_NUMBER: + if (ngx_rtmp_amf_put(ctx, + ngx_rtmp_amf_reverse_copy(buf, + data, 8), 8) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_BOOLEAN: + if (ngx_rtmp_amf_put(ctx, data, 1) != NGX_OK) { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_STRING: + if (len == 0 && data) { + len = (uint16_t) ngx_strlen((u_char*) data); + } + + if (ngx_rtmp_amf_put(ctx, + ngx_rtmp_amf_reverse_copy(buf, + &len, 2), 2) != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_rtmp_amf_put(ctx, data, len) != NGX_OK) { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_NULL: + case NGX_RTMP_AMF_ARRAY_NULL: + break; + + case NGX_RTMP_AMF_MIXED_ARRAY: + max_index = 0; + if (ngx_rtmp_amf_put(ctx, &max_index, 4) != NGX_OK) { + return NGX_ERROR; + } + + case NGX_RTMP_AMF_OBJECT: + type8 = NGX_RTMP_AMF_END; + if (ngx_rtmp_amf_write_object(ctx, data, + elts[n].len / sizeof(ngx_rtmp_amf_elt_t)) != NGX_OK + || ngx_rtmp_amf_put(ctx, &type8, 1) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_ARRAY: + if (ngx_rtmp_amf_write_array(ctx, data, + elts[n].len / sizeof(ngx_rtmp_amf_elt_t)) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_INT8: + if (ngx_rtmp_amf_put(ctx, data, 1) != NGX_OK) { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_INT16: + if (ngx_rtmp_amf_put(ctx, + ngx_rtmp_amf_reverse_copy(buf, + data, 2), 2) != NGX_OK) + { + return NGX_ERROR; + } + break; + + case NGX_RTMP_AMF_INT32: + if (ngx_rtmp_amf_put(ctx, + ngx_rtmp_amf_reverse_copy(buf, + data, 4), 4) != NGX_OK) + { + return NGX_ERROR; + } + break; + + default: + return NGX_ERROR; + } + } + + return NGX_OK; +} + diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_amf.h b/debian/modules/nginx-rtmp/ngx_rtmp_amf.h new file mode 100644 index 0000000..8f70a12 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_amf.h @@ -0,0 +1,71 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_AMF_H_INCLUDED_ +#define _NGX_RTMP_AMF_H_INCLUDED_ + + +#include +#include + + +/* basic types */ +#define NGX_RTMP_AMF_NUMBER 0x00 +#define NGX_RTMP_AMF_BOOLEAN 0x01 +#define NGX_RTMP_AMF_STRING 0x02 +#define NGX_RTMP_AMF_OBJECT 0x03 +#define NGX_RTMP_AMF_NULL 0x05 +#define NGX_RTMP_AMF_ARRAY_NULL 0x06 +#define NGX_RTMP_AMF_MIXED_ARRAY 0x08 +#define NGX_RTMP_AMF_END 0x09 +#define NGX_RTMP_AMF_ARRAY 0x0a + +/* extended types */ +#define NGX_RTMP_AMF_INT8 0x0100 +#define NGX_RTMP_AMF_INT16 0x0101 +#define NGX_RTMP_AMF_INT32 0x0102 +#define NGX_RTMP_AMF_VARIANT_ 0x0103 + +/* r/w flags */ +#define NGX_RTMP_AMF_OPTIONAL 0x1000 +#define NGX_RTMP_AMF_TYPELESS 0x2000 +#define NGX_RTMP_AMF_CONTEXT 0x4000 + +#define NGX_RTMP_AMF_VARIANT (NGX_RTMP_AMF_VARIANT_\ + |NGX_RTMP_AMF_TYPELESS) + + +typedef struct { + ngx_int_t type; + ngx_str_t name; + void *data; + size_t len; +} ngx_rtmp_amf_elt_t; + + +typedef ngx_chain_t * (*ngx_rtmp_amf_alloc_pt)(void *arg); + + +typedef struct { + ngx_chain_t *link, *first; + size_t offset; + ngx_rtmp_amf_alloc_pt alloc; + void *arg; + ngx_log_t *log; +} ngx_rtmp_amf_ctx_t; + + +/* reading AMF */ +ngx_int_t ngx_rtmp_amf_read(ngx_rtmp_amf_ctx_t *ctx, + ngx_rtmp_amf_elt_t *elts, size_t nelts); + +/* writing AMF */ +ngx_int_t ngx_rtmp_amf_write(ngx_rtmp_amf_ctx_t *ctx, + ngx_rtmp_amf_elt_t *elts, size_t nelts); + + +#endif /* _NGX_RTMP_AMF_H_INCLUDED_ */ + diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c new file mode 100644 index 0000000..60c85d7 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c @@ -0,0 +1,578 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_relay_module.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_delete_stream_pt next_delete_stream; + + +static ngx_int_t ngx_rtmp_auto_push_init_process(ngx_cycle_t *cycle); +static void ngx_rtmp_auto_push_exit_process(ngx_cycle_t *cycle); +static void * ngx_rtmp_auto_push_create_conf(ngx_cycle_t *cf); +static char * ngx_rtmp_auto_push_init_conf(ngx_cycle_t *cycle, void *conf); +#if (NGX_HAVE_UNIX_DOMAIN) +static ngx_int_t ngx_rtmp_auto_push_publish(ngx_rtmp_session_t *s, + ngx_rtmp_publish_t *v); +static ngx_int_t ngx_rtmp_auto_push_delete_stream(ngx_rtmp_session_t *s, + ngx_rtmp_delete_stream_t *v); +#endif + + +typedef struct ngx_rtmp_auto_push_ctx_s ngx_rtmp_auto_push_ctx_t; + +struct ngx_rtmp_auto_push_ctx_s { + ngx_int_t *slots; /* NGX_MAX_PROCESSES */ + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; + ngx_event_t push_evt; +}; + + +typedef struct { + ngx_flag_t auto_push; + ngx_str_t socket_dir; + ngx_msec_t push_reconnect; +} ngx_rtmp_auto_push_conf_t; + + +static ngx_command_t ngx_rtmp_auto_push_commands[] = { + + { ngx_string("rtmp_auto_push"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + 0, + offsetof(ngx_rtmp_auto_push_conf_t, auto_push), + NULL }, + + { ngx_string("rtmp_auto_push_reconnect"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + 0, + offsetof(ngx_rtmp_auto_push_conf_t, push_reconnect), + NULL }, + + { ngx_string("rtmp_socket_dir"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + 0, + offsetof(ngx_rtmp_auto_push_conf_t, socket_dir), + NULL }, + + ngx_null_command +}; + + +static ngx_core_module_t ngx_rtmp_auto_push_module_ctx = { + ngx_string("rtmp_auto_push"), + ngx_rtmp_auto_push_create_conf, /* create conf */ + ngx_rtmp_auto_push_init_conf /* init conf */ +}; + + +ngx_module_t ngx_rtmp_auto_push_module = { + NGX_MODULE_V1, + &ngx_rtmp_auto_push_module_ctx, /* module context */ + ngx_rtmp_auto_push_commands, /* module directives */ + NGX_CORE_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_rtmp_auto_push_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + ngx_rtmp_auto_push_exit_process, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_rtmp_module_t ngx_rtmp_auto_push_index_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_auto_push_index_module = { + NGX_MODULE_V1, + &ngx_rtmp_auto_push_index_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_RTMP_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 +}; + + +#define NGX_RTMP_AUTO_PUSH_SOCKNAME "nginx-rtmp" + + +static ngx_int_t +ngx_rtmp_auto_push_init_process(ngx_cycle_t *cycle) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_rtmp_auto_push_conf_t *apcf; + ngx_listening_t *ls, *lss; + struct sockaddr_un *saun; + int reuseaddr; + ngx_socket_t s; + size_t n; + ngx_file_info_t fi; + + if (ngx_process != NGX_PROCESS_WORKER) { + return NGX_OK; + } + + apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_rtmp_auto_push_module); + if (apcf->auto_push == 0) { + return NGX_OK; + } + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_auto_push_publish; + + next_delete_stream = ngx_rtmp_delete_stream; + ngx_rtmp_delete_stream = ngx_rtmp_auto_push_delete_stream; + + reuseaddr = 1; + s = (ngx_socket_t) -1; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, cycle->log, 0, + "auto_push: creating sockets"); + + /*TODO: clone all RTMP listenings? */ + ls = cycle->listening.elts; + lss = NULL; + for (n = 0; n < cycle->listening.nelts; ++n, ++ls) { + if (ls->handler == ngx_rtmp_init_connection) { + lss = ls; + break; + } + } + + if (lss == NULL) { + return NGX_OK; + } + + ls = ngx_array_push(&cycle->listening); + if (ls == NULL) { + return NGX_ERROR; + } + + *ls = *lss; + + /* Disable unix socket client address extraction + * from accept call + * Nginx generates bad addr_text with this enabled */ + ls->addr_ntop = 0; + + ls->socklen = sizeof(struct sockaddr_un); + saun = ngx_pcalloc(cycle->pool, ls->socklen); + ls->sockaddr = (struct sockaddr *) saun; + if (ls->sockaddr == NULL) { + return NGX_ERROR; + } + saun->sun_family = AF_UNIX; + *ngx_snprintf((u_char *) saun->sun_path, sizeof(saun->sun_path), + "%V/" NGX_RTMP_AUTO_PUSH_SOCKNAME ".%i", + &apcf->socket_dir, ngx_process_slot) + = 0; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, cycle->log, 0, + "auto_push: create socket '%s'", + saun->sun_path); + + if (ngx_file_info(saun->sun_path, &fi) != ENOENT) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, cycle->log, 0, + "auto_push: delete existing socket '%s'", + saun->sun_path); + ngx_delete_file(saun->sun_path); + } + + ngx_str_set(&ls->addr_text, "worker_socket"); + + s = ngx_socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_socket_n " worker_socket failed"); + return NGX_ERROR; + } + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "setsockopt(SO_REUSEADDR) worker_socket failed"); + goto sock_error; + } + + if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { + if (ngx_nonblocking(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_nonblocking_n " worker_socket failed"); + return NGX_ERROR; + } + } + + if (bind(s, (struct sockaddr *) saun, sizeof(*saun)) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_nonblocking_n " worker_socket bind failed"); + goto sock_error; + } + + if (listen(s, NGX_LISTEN_BACKLOG) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "listen() to worker_socket, backlog %d failed", + NGX_LISTEN_BACKLOG); + goto sock_error; + } + + ls->fd = s; + ls->listen = 1; + + return NGX_OK; + +sock_error: + if (s != (ngx_socket_t) -1 && ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_close_socket_n " worker_socket failed"); + } + ngx_delete_file(saun->sun_path); + + return NGX_ERROR; + +#else /* NGX_HAVE_UNIX_DOMAIN */ + + return NGX_OK; + +#endif /* NGX_HAVE_UNIX_DOMAIN */ +} + + +static void +ngx_rtmp_auto_push_exit_process(ngx_cycle_t *cycle) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_rtmp_auto_push_conf_t *apcf; + u_char path[NGX_MAX_PATH]; + + apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(cycle->conf_ctx, + ngx_rtmp_auto_push_module); + if (apcf->auto_push == 0) { + return; + } + *ngx_snprintf(path, sizeof(path), + "%V/" NGX_RTMP_AUTO_PUSH_SOCKNAME ".%i", + &apcf->socket_dir, ngx_process_slot) + = 0; + + ngx_delete_file(path); + +#endif +} + + +static void * +ngx_rtmp_auto_push_create_conf(ngx_cycle_t *cycle) +{ + ngx_rtmp_auto_push_conf_t *apcf; + + apcf = ngx_pcalloc(cycle->pool, sizeof(ngx_rtmp_auto_push_conf_t)); + if (apcf == NULL) { + return NULL; + } + + apcf->auto_push = NGX_CONF_UNSET; + apcf->push_reconnect = NGX_CONF_UNSET_MSEC; + + return apcf; +} + + +static char * +ngx_rtmp_auto_push_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_rtmp_auto_push_conf_t *apcf = conf; + + ngx_conf_init_value(apcf->auto_push, 0); + ngx_conf_init_msec_value(apcf->push_reconnect, 100); + + if (apcf->socket_dir.len == 0) { + ngx_str_set(&apcf->socket_dir, "/tmp"); + } + + return NGX_CONF_OK; +} + + +#if (NGX_HAVE_UNIX_DOMAIN) +static void +ngx_rtmp_auto_push_reconnect(ngx_event_t *ev) +{ + ngx_rtmp_session_t *s = ev->data; + + ngx_rtmp_auto_push_conf_t *apcf; + ngx_rtmp_auto_push_ctx_t *ctx; + ngx_int_t *slot; + ngx_int_t n; + ngx_rtmp_relay_target_t at; + u_char path[sizeof("unix:") + NGX_MAX_PATH]; + u_char flash_ver[sizeof("APSH ,") + + NGX_INT_T_LEN * 2]; + u_char play_path[NGX_RTMP_MAX_NAME]; + ngx_str_t name; + u_char *p; + ngx_str_t *u; + ngx_pid_t pid; + ngx_int_t npushed; + ngx_core_conf_t *ccf; + ngx_file_info_t fi; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "auto_push: reconnect"); + + apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_rtmp_auto_push_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_index_module); + if (ctx == NULL) { + return; + } + + name.data = ctx->name; + name.len = ngx_strlen(name.data); + + ngx_memzero(&at, sizeof(at)); + ngx_str_set(&at.page_url, "nginx-auto-push"); + at.tag = &ngx_rtmp_auto_push_module; + + if (ctx->args[0]) { + at.play_path.data = play_path; + at.play_path.len = ngx_snprintf(play_path, sizeof(play_path), + "%s?%s", ctx->name, ctx->args) - + play_path; + } + + slot = ctx->slots; + npushed = 0; + + for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++slot) { + if (n == ngx_process_slot) { + continue; + } + + pid = ngx_processes[n].pid; + if (pid == 0 || pid == NGX_INVALID_PID) { + continue; + } + + if (*slot) { + npushed++; + continue; + } + + at.data = &ngx_processes[n]; + + ngx_memzero(&at.url, sizeof(at.url)); + u = &at.url.url; + p = ngx_snprintf(path, sizeof(path) - 1, + "unix:%V/" NGX_RTMP_AUTO_PUSH_SOCKNAME ".%i", + &apcf->socket_dir, n); + *p = 0; + + if (ngx_file_info(path + sizeof("unix:") - 1, &fi) != NGX_OK) { + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "auto_push: " ngx_file_info_n " failed: " + "slot=%i pid=%P socket='%s'" "url='%V' name='%s'", + n, pid, path, u, ctx->name); + continue; + } + + u->data = path; + u->len = p - path; + if (ngx_parse_url(s->connection->pool, &at.url) != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "auto_push: auto-push parse_url failed " + "url='%V' name='%s'", + u, ctx->name); + continue; + } + + p = ngx_snprintf(flash_ver, sizeof(flash_ver) - 1, "APSH %i,%i", + (ngx_int_t) ngx_process_slot, (ngx_int_t) ngx_pid); + at.flash_ver.data = flash_ver; + at.flash_ver.len = p - flash_ver; + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "auto_push: connect slot=%i pid=%P socket='%s' name='%s'", + n, pid, path, ctx->name); + + if (ngx_rtmp_relay_push(s, &name, &at) == NGX_OK) { + *slot = 1; + npushed++; + continue; + } + + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "auto_push: connect failed: slot=%i pid=%P socket='%s'" + "url='%V' name='%s'", + n, pid, path, u, ctx->name); + } + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "auto_push: pushed=%i total=%i failed=%i", + npushed, ccf->worker_processes, + ccf->worker_processes - 1 - npushed); + + if (ccf->worker_processes == npushed + 1) { + return; + } + + /* several workers failed */ + + slot = ctx->slots; + + for (n = 0; n < NGX_MAX_PROCESSES; ++n, ++slot) { + pid = ngx_processes[n].pid; + + if (n == ngx_process_slot || *slot == 1 || + pid == 0 || pid == NGX_INVALID_PID) + { + continue; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "auto_push: connect failed: slot=%i pid=%P name='%s'", + n, pid, ctx->name); + } + + if (!ctx->push_evt.timer_set) { + ngx_add_timer(&ctx->push_evt, apcf->push_reconnect); + } +} + + +static ngx_int_t +ngx_rtmp_auto_push_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_auto_push_conf_t *apcf; + ngx_rtmp_auto_push_ctx_t *ctx; + + if (s->auto_pushed || (s->relay && !s->static_relay)) { + goto next; + } + + apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_rtmp_auto_push_module); + if (apcf->auto_push == 0) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_index_module); + if (ctx == NULL) { + ctx = ngx_palloc(s->connection->pool, + sizeof(ngx_rtmp_auto_push_ctx_t)); + if (ctx == NULL) { + goto next; + } + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_auto_push_index_module); + + } + ngx_memzero(ctx, sizeof(*ctx)); + + ctx->push_evt.data = s; + ctx->push_evt.log = s->connection->log; + ctx->push_evt.handler = ngx_rtmp_auto_push_reconnect; + + ctx->slots = ngx_pcalloc(s->connection->pool, + sizeof(ngx_int_t) * NGX_MAX_PROCESSES); + if (ctx->slots == NULL) { + goto next; + } + + ngx_memcpy(ctx->name, v->name, sizeof(ctx->name)); + ngx_memcpy(ctx->args, v->args, sizeof(ctx->args)); + + ngx_rtmp_auto_push_reconnect(&ctx->push_evt); + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_auto_push_delete_stream(ngx_rtmp_session_t *s, + ngx_rtmp_delete_stream_t *v) +{ + ngx_rtmp_auto_push_conf_t *apcf; + ngx_rtmp_auto_push_ctx_t *ctx, *pctx; + ngx_rtmp_relay_ctx_t *rctx; + ngx_int_t slot; + + apcf = (ngx_rtmp_auto_push_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_rtmp_auto_push_module); + if (apcf->auto_push == 0) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_auto_push_index_module); + if (ctx) { + if (ctx->push_evt.timer_set) { + ngx_del_timer(&ctx->push_evt); + } + goto next; + } + + /* skip non-relays & publishers */ + rctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (rctx == NULL || + rctx->tag != &ngx_rtmp_auto_push_module || + rctx->publish == NULL) + { + goto next; + } + + slot = (ngx_process_t *) rctx->data - &ngx_processes[0]; + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "auto_push: disconnect slot=%i app='%V' name='%V'", + slot, &rctx->app, &rctx->name); + + pctx = ngx_rtmp_get_module_ctx(rctx->publish->session, + ngx_rtmp_auto_push_index_module); + if (pctx == NULL) { + goto next; + } + + pctx->slots[slot] = 0; + + /* push reconnect */ + if (!pctx->push_evt.timer_set) { + ngx_add_timer(&pctx->push_evt, apcf->push_reconnect); + } + +next: + return next_delete_stream(s, v); +} +#endif /* NGX_HAVE_UNIX_DOMAIN */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c b/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c new file mode 100644 index 0000000..82f9f0d --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c @@ -0,0 +1,26 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_bandwidth.h" + + +void +ngx_rtmp_update_bandwidth(ngx_rtmp_bandwidth_t *bw, uint32_t bytes) +{ + if (ngx_cached_time->sec > bw->intl_end) { + bw->bandwidth = ngx_cached_time->sec > + bw->intl_end + NGX_RTMP_BANDWIDTH_INTERVAL + ? 0 + : bw->intl_bytes / NGX_RTMP_BANDWIDTH_INTERVAL; + bw->intl_bytes = 0; + bw->intl_end = ngx_cached_time->sec + NGX_RTMP_BANDWIDTH_INTERVAL; + } + + bw->bytes += bytes; + bw->intl_bytes += bytes; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h b/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h new file mode 100644 index 0000000..b498482 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h @@ -0,0 +1,31 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_BANDWIDTH_H_INCLUDED_ +#define _NGX_RTMP_BANDWIDTH_H_INCLUDED_ + + +#include +#include + + +/* Bandwidth update interval in seconds */ +#define NGX_RTMP_BANDWIDTH_INTERVAL 10 + + +typedef struct { + uint64_t bytes; + uint64_t bandwidth; /* bytes/sec */ + + time_t intl_end; + uint64_t intl_bytes; +} ngx_rtmp_bandwidth_t; + + +void ngx_rtmp_update_bandwidth(ngx_rtmp_bandwidth_t *bw, uint32_t bytes); + + +#endif /* _NGX_RTMP_BANDWIDTH_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bitop.c b/debian/modules/nginx-rtmp/ngx_rtmp_bitop.c new file mode 100644 index 0000000..855d425 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_bitop.c @@ -0,0 +1,63 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_bitop.h" + + +void +ngx_rtmp_bit_init_reader(ngx_rtmp_bit_reader_t *br, u_char *pos, u_char *last) +{ + ngx_memzero(br, sizeof(ngx_rtmp_bit_reader_t)); + + br->pos = pos; + br->last = last; +} + + +uint64_t +ngx_rtmp_bit_read(ngx_rtmp_bit_reader_t *br, ngx_uint_t n) +{ + uint64_t v; + ngx_uint_t d; + + v = 0; + + while (n) { + + if (br->pos >= br->last) { + br->err = 1; + return 0; + } + + d = (br->offs + n > 8 ? (ngx_uint_t) (8 - br->offs) : n); + + v <<= d; + v += (*br->pos >> (8 - br->offs - d)) & ((u_char) 0xff >> (8 - d)); + + br->offs += d; + n -= d; + + if (br->offs == 8) { + br->pos++; + br->offs = 0; + } + } + + return v; +} + + +uint64_t +ngx_rtmp_bit_read_golomb(ngx_rtmp_bit_reader_t *br) +{ + ngx_uint_t n; + + for (n = 0; ngx_rtmp_bit_read(br, 1) == 0 && !br->err; n++); + + return ((uint64_t) 1 << n) + ngx_rtmp_bit_read(br, n) - 1; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bitop.h b/debian/modules/nginx-rtmp/ngx_rtmp_bitop.h new file mode 100644 index 0000000..c954a35 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_bitop.h @@ -0,0 +1,46 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_BITOP_H_INCLUDED_ +#define _NGX_RTMP_BITOP_H_INCLUDED_ + + +#include +#include + + +typedef struct { + u_char *pos; + u_char *last; + ngx_uint_t offs; + ngx_uint_t err; +} ngx_rtmp_bit_reader_t; + + +void ngx_rtmp_bit_init_reader(ngx_rtmp_bit_reader_t *br, u_char *pos, + u_char *last); +uint64_t ngx_rtmp_bit_read(ngx_rtmp_bit_reader_t *br, ngx_uint_t n); +uint64_t ngx_rtmp_bit_read_golomb(ngx_rtmp_bit_reader_t *br); + + +#define ngx_rtmp_bit_read_err(br) ((br)->err) + +#define ngx_rtmp_bit_read_eof(br) ((br)->pos == (br)->last) + +#define ngx_rtmp_bit_read_8(br) \ + ((uint8_t) ngx_rtmp_bit_read(br, 8)) + +#define ngx_rtmp_bit_read_16(br) \ + ((uint16_t) ngx_rtmp_bit_read(br, 16)) + +#define ngx_rtmp_bit_read_32(br) \ + ((uint32_t) ngx_rtmp_bit_read(br, 32)) + +#define ngx_rtmp_bit_read_64(br) \ + ((uint64_t) ngx_rtmp_read(br, 64)) + + +#endif /* _NGX_RTMP_BITOP_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c new file mode 100644 index 0000000..13f6677 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c @@ -0,0 +1,856 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_streams.h" + + +#define NGX_RTMP_FMS_VERSION "FMS/3,0,1,123" +#define NGX_RTMP_CAPABILITIES 31 + + +static ngx_int_t ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, + ngx_rtmp_connect_t *v); +static ngx_int_t ngx_rtmp_cmd_disconnect(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_cmd_create_stream(ngx_rtmp_session_t *s, + ngx_rtmp_create_stream_t *v); +static ngx_int_t ngx_rtmp_cmd_close_stream(ngx_rtmp_session_t *s, + ngx_rtmp_close_stream_t *v); +static ngx_int_t ngx_rtmp_cmd_delete_stream(ngx_rtmp_session_t *s, + ngx_rtmp_delete_stream_t *v); +static ngx_int_t ngx_rtmp_cmd_publish(ngx_rtmp_session_t *s, + ngx_rtmp_publish_t *v); +static ngx_int_t ngx_rtmp_cmd_play(ngx_rtmp_session_t *s, + ngx_rtmp_play_t *v); +static ngx_int_t ngx_rtmp_cmd_seek(ngx_rtmp_session_t *s, + ngx_rtmp_seek_t *v); +static ngx_int_t ngx_rtmp_cmd_pause(ngx_rtmp_session_t *s, + ngx_rtmp_pause_t *v); + + +static ngx_int_t ngx_rtmp_cmd_stream_begin(ngx_rtmp_session_t *s, + ngx_rtmp_stream_begin_t *v); +static ngx_int_t ngx_rtmp_cmd_stream_eof(ngx_rtmp_session_t *s, + ngx_rtmp_stream_eof_t *v); +static ngx_int_t ngx_rtmp_cmd_stream_dry(ngx_rtmp_session_t *s, + ngx_rtmp_stream_dry_t *v); +static ngx_int_t ngx_rtmp_cmd_recorded(ngx_rtmp_session_t *s, + ngx_rtmp_recorded_t *v); +static ngx_int_t ngx_rtmp_cmd_set_buflen(ngx_rtmp_session_t *s, + ngx_rtmp_set_buflen_t *v); + + +ngx_rtmp_connect_pt ngx_rtmp_connect; +ngx_rtmp_disconnect_pt ngx_rtmp_disconnect; +ngx_rtmp_create_stream_pt ngx_rtmp_create_stream; +ngx_rtmp_close_stream_pt ngx_rtmp_close_stream; +ngx_rtmp_delete_stream_pt ngx_rtmp_delete_stream; +ngx_rtmp_publish_pt ngx_rtmp_publish; +ngx_rtmp_play_pt ngx_rtmp_play; +ngx_rtmp_seek_pt ngx_rtmp_seek; +ngx_rtmp_pause_pt ngx_rtmp_pause; + + +ngx_rtmp_stream_begin_pt ngx_rtmp_stream_begin; +ngx_rtmp_stream_eof_pt ngx_rtmp_stream_eof; +ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry; +ngx_rtmp_recorded_pt ngx_rtmp_recorded; +ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen; + + +static ngx_int_t ngx_rtmp_cmd_postconfiguration(ngx_conf_t *cf); + + +static ngx_rtmp_module_t ngx_rtmp_cmd_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_cmd_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_cmd_module = { + NGX_MODULE_V1, + &ngx_rtmp_cmd_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_RTMP_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_rtmp_cmd_fill_args(u_char name[NGX_RTMP_MAX_NAME], + u_char args[NGX_RTMP_MAX_ARGS]) +{ + u_char *p; + + p = (u_char *)ngx_strchr(name, '?'); + if (p == NULL) { + return; + } + + *p++ = 0; + ngx_cpystrn(args, p, NGX_RTMP_MAX_ARGS); +} + + +static ngx_int_t +ngx_rtmp_cmd_connect_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + size_t len; + + static ngx_rtmp_connect_t v; + + static ngx_rtmp_amf_elt_t in_cmd[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("app"), + v.app, sizeof(v.app) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("flashVer"), + v.flashver, sizeof(v.flashver) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("swfUrl"), + v.swf_url, sizeof(v.swf_url) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("tcUrl"), + v.tc_url, sizeof(v.tc_url) }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audioCodecs"), + &v.acodecs, sizeof(v.acodecs) }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videoCodecs"), + &v.vcodecs, sizeof(v.vcodecs) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("pageUrl"), + v.page_url, sizeof(v.page_url) }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("objectEncoding"), + &v.object_encoding, 0}, + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_cmd, sizeof(in_cmd) }, + }; + + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + len = ngx_strlen(v.app); + if (len > 10 && !ngx_memcmp(v.app + len - 10, "/_definst_", 10)) { + v.app[len - 10] = 0; + } else if (len && v.app[len - 1] == '/') { + v.app[len - 1] = 0; + } + + ngx_rtmp_cmd_fill_args(v.app, v.args); + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "connect: app='%s' args='%s' flashver='%s' swf_url='%s' " + "tc_url='%s' page_url='%s' acodecs=%uD vcodecs=%uD " + "object_encoding=%ui", + v.app, v.args, v.flashver, v.swf_url, v.tc_url, v.page_url, + (uint32_t)v.acodecs, (uint32_t)v.vcodecs, + (ngx_int_t)v.object_encoding); + + return ngx_rtmp_connect(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_core_app_conf_t **cacfp; + ngx_uint_t n; + ngx_rtmp_header_t h; + u_char *p; + + static double trans; + static double capabilities = NGX_RTMP_CAPABILITIES; + static double object_encoding = 0; + + static ngx_rtmp_amf_elt_t out_obj[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("fmsVer"), + NGX_RTMP_FMS_VERSION, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("capabilities"), + &capabilities, 0 }, + }; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + "status", 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("code"), + "NetConnection.Connect.Success", 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("description"), + "Connection succeeded.", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("objectEncoding"), + &object_encoding, 0 } + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "_result", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_obj, sizeof(out_obj) }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, sizeof(out_inf) }, + }; + + if (s->connected) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "connect: duplicate connection"); + return NGX_ERROR; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + trans = v->trans; + + /* fill session parameters */ + s->connected = 1; + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_CSID_AMF_INI; + h.type = NGX_RTMP_MSG_AMF_CMD; + + +#define NGX_RTMP_SET_STRPAR(name) \ + s->name.len = ngx_strlen(v->name); \ + s->name.data = ngx_palloc(s->connection->pool, s->name.len); \ + ngx_memcpy(s->name.data, v->name, s->name.len) + + NGX_RTMP_SET_STRPAR(app); + NGX_RTMP_SET_STRPAR(args); + NGX_RTMP_SET_STRPAR(flashver); + NGX_RTMP_SET_STRPAR(swf_url); + NGX_RTMP_SET_STRPAR(tc_url); + NGX_RTMP_SET_STRPAR(page_url); + +#undef NGX_RTMP_SET_STRPAR + + p = ngx_strlchr(s->app.data, s->app.data + s->app.len, '?'); + if (p) { + s->app.len = (p - s->app.data); + } + + s->acodecs = (uint32_t) v->acodecs; + s->vcodecs = (uint32_t) v->vcodecs; + + /* find application & set app_conf */ + cacfp = cscf->applications.elts; + for(n = 0; n < cscf->applications.nelts; ++n, ++cacfp) { + if ((*cacfp)->name.len == s->app.len && + ngx_strncmp((*cacfp)->name.data, s->app.data, s->app.len) == 0) + { + /* found app! */ + s->app_conf = (*cacfp)->app_conf; + break; + } + } + + if (s->app_conf == NULL) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "connect: application not found: '%V'", &s->app); + return NGX_ERROR; + } + + object_encoding = v->object_encoding; + + return ngx_rtmp_send_ack_size(s, cscf->ack_window) != NGX_OK || + ngx_rtmp_send_bandwidth(s, cscf->ack_window, + NGX_RTMP_LIMIT_DYNAMIC) != NGX_OK || + ngx_rtmp_send_chunk_size(s, cscf->chunk_size) != NGX_OK || + ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) + != NGX_OK ? NGX_ERROR : NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_create_stream_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_create_stream_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, sizeof(v.trans) }, + }; + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "createStream"); + + return ngx_rtmp_create_stream(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_create_stream(ngx_rtmp_session_t *s, ngx_rtmp_create_stream_t *v) +{ + /* support one message stream per connection */ + static double stream; + static double trans; + ngx_rtmp_header_t h; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "_result", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &stream, sizeof(stream) }, + }; + + trans = v->trans; + stream = NGX_RTMP_MSID; + + ngx_memzero(&h, sizeof(h)); + + h.csid = NGX_RTMP_CSID_AMF_INI; + h.type = NGX_RTMP_MSG_AMF_CMD; + + return ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) == NGX_OK ? + NGX_DONE : NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_cmd_close_stream_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_close_stream_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.stream, 0 }, + }; + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "closeStream"); + + return ngx_rtmp_close_stream(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_delete_stream_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_delete_stream_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.stream, 0 }, + }; + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + return ngx_rtmp_delete_stream(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v) +{ + ngx_rtmp_close_stream_t cv; + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "deleteStream"); + + cv.stream = 0; + + return ngx_rtmp_close_stream(s, &cv); +} + + +static ngx_int_t +ngx_rtmp_cmd_publish_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_publish_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + /* transaction is always 0 */ + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + &v.name, sizeof(v.name) }, + + { NGX_RTMP_AMF_OPTIONAL | NGX_RTMP_AMF_STRING, + ngx_null_string, + &v.type, sizeof(v.type) }, + }; + + ngx_memzero(&v, sizeof(v)); + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_rtmp_cmd_fill_args(v.name, v.args); + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "publish: name='%s' args='%s' type=%s silent=%d", + v.name, v.args, v.type, v.silent); + + return ngx_rtmp_publish(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + return NGX_OK; +} + +static ngx_int_t +ngx_rtmp_cmd_play_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_play_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + /* transaction is always 0 */ + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + &v.name, sizeof(v.name) }, + + { NGX_RTMP_AMF_OPTIONAL | NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.start, 0 }, + + { NGX_RTMP_AMF_OPTIONAL | NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.duration, 0 }, + + { NGX_RTMP_AMF_OPTIONAL | NGX_RTMP_AMF_BOOLEAN, + ngx_null_string, + &v.reset, 0 } + }; + + ngx_memzero(&v, sizeof(v)); + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_rtmp_cmd_fill_args(v.name, v.args); + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "play: name='%s' args='%s' start=%i duration=%i " + "reset=%i silent=%i", + v.name, v.args, (ngx_int_t) v.start, + (ngx_int_t) v.duration, (ngx_int_t) v.reset, + (ngx_int_t) v.silent); + + return ngx_rtmp_play(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_play2_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_play_t v; + static ngx_rtmp_close_stream_t vc; + + static ngx_rtmp_amf_elt_t in_obj[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_string("start"), + &v.start, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("streamName"), + &v.name, sizeof(v.name) }, + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + /* transaction is always 0 */ + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + &in_obj, sizeof(in_obj) } + }; + + ngx_memzero(&v, sizeof(v)); + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_rtmp_cmd_fill_args(v.name, v.args); + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "play2: name='%s' args='%s' start=%i", + v.name, v.args, (ngx_int_t) v.start); + + /* continue from current timestamp */ + + if (v.start < 0) { + v.start = s->current_time; + } + + ngx_memzero(&vc, sizeof(vc)); + + /* close_stream should be synchronous */ + ngx_rtmp_close_stream(s, &vc); + + return ngx_rtmp_play(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_pause_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_pause_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_BOOLEAN, + ngx_null_string, + &v.pause, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.position, 0 }, + }; + + ngx_memzero(&v, sizeof(v)); + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "pause: pause=%i position=%i", + (ngx_int_t) v.pause, (ngx_int_t) v.position); + + return ngx_rtmp_pause(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_disconnect_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, "disconnect"); + + return ngx_rtmp_disconnect(s); +} + + +static ngx_int_t +ngx_rtmp_cmd_disconnect(ngx_rtmp_session_t *s) +{ + return ngx_rtmp_delete_stream(s, NULL); +} + + +static ngx_int_t +ngx_rtmp_cmd_seek_init(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + static ngx_rtmp_seek_t v; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + /* transaction is always 0 */ + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.offset, sizeof(v.offset) }, + }; + + ngx_memzero(&v, sizeof(v)); + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "seek: offset=%i", (ngx_int_t) v.offset); + + return ngx_rtmp_seek(s, &v); +} + + +static ngx_int_t +ngx_rtmp_cmd_seek(ngx_rtmp_session_t *s, ngx_rtmp_seek_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_eof_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_stream_dry(ngx_rtmp_session_t *s, ngx_rtmp_stream_dry_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_recorded(ngx_rtmp_session_t *s, + ngx_rtmp_recorded_t *v) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_cmd_set_buflen(ngx_rtmp_session_t *s, ngx_rtmp_set_buflen_t *v) +{ + return NGX_OK; +} + + +static ngx_rtmp_amf_handler_t ngx_rtmp_cmd_map[] = { + { ngx_string("connect"), ngx_rtmp_cmd_connect_init }, + { ngx_string("createStream"), ngx_rtmp_cmd_create_stream_init }, + { ngx_string("closeStream"), ngx_rtmp_cmd_close_stream_init }, + { ngx_string("deleteStream"), ngx_rtmp_cmd_delete_stream_init }, + { ngx_string("publish"), ngx_rtmp_cmd_publish_init }, + { ngx_string("play"), ngx_rtmp_cmd_play_init }, + { ngx_string("play2"), ngx_rtmp_cmd_play2_init }, + { ngx_string("seek"), ngx_rtmp_cmd_seek_init }, + { ngx_string("pause"), ngx_rtmp_cmd_pause_init }, + { ngx_string("pauseraw"), ngx_rtmp_cmd_pause_init }, +}; + + +static ngx_int_t +ngx_rtmp_cmd_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + ngx_rtmp_amf_handler_t *ch, *bh; + size_t n, ncalls; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + /* redirect disconnects to deleteStream + * to free client modules from registering + * disconnect callback */ + + h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_rtmp_cmd_disconnect_init; + + /* register AMF callbacks */ + + ncalls = sizeof(ngx_rtmp_cmd_map) / sizeof(ngx_rtmp_cmd_map[0]); + + ch = ngx_array_push_n(&cmcf->amf, ncalls); + if (ch == NULL) { + return NGX_ERROR; + } + + bh = ngx_rtmp_cmd_map; + + for(n = 0; n < ncalls; ++n, ++ch, ++bh) { + *ch = *bh; + } + + ngx_rtmp_connect = ngx_rtmp_cmd_connect; + ngx_rtmp_disconnect = ngx_rtmp_cmd_disconnect; + ngx_rtmp_create_stream = ngx_rtmp_cmd_create_stream; + ngx_rtmp_close_stream = ngx_rtmp_cmd_close_stream; + ngx_rtmp_delete_stream = ngx_rtmp_cmd_delete_stream; + ngx_rtmp_publish = ngx_rtmp_cmd_publish; + ngx_rtmp_play = ngx_rtmp_cmd_play; + ngx_rtmp_seek = ngx_rtmp_cmd_seek; + ngx_rtmp_pause = ngx_rtmp_cmd_pause; + + ngx_rtmp_stream_begin = ngx_rtmp_cmd_stream_begin; + ngx_rtmp_stream_eof = ngx_rtmp_cmd_stream_eof; + ngx_rtmp_stream_dry = ngx_rtmp_cmd_stream_dry; + ngx_rtmp_recorded = ngx_rtmp_cmd_recorded; + ngx_rtmp_set_buflen = ngx_rtmp_cmd_set_buflen; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h new file mode 100644 index 0000000..4a0b955 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h @@ -0,0 +1,151 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_CMD_H_INCLUDED_ +#define _NGX_RTMP_CMD_H_INCLUDED_ + + +#include +#include +#include +#include "ngx_rtmp.h" + + +#define NGX_RTMP_MAX_NAME 256 +#define NGX_RTMP_MAX_URL 256 +#define NGX_RTMP_MAX_ARGS NGX_RTMP_MAX_NAME + + +/* Basic RTMP call support */ + +typedef struct { + double trans; + u_char app[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; + u_char flashver[32]; + u_char swf_url[NGX_RTMP_MAX_URL]; + u_char tc_url[NGX_RTMP_MAX_URL]; + double acodecs; + double vcodecs; + u_char page_url[NGX_RTMP_MAX_URL]; + double object_encoding; +} ngx_rtmp_connect_t; + + +typedef struct { + double trans; + double stream; +} ngx_rtmp_create_stream_t; + + +typedef struct { + double stream; +} ngx_rtmp_delete_stream_t; + + +typedef struct { + double stream; +} ngx_rtmp_close_stream_t; + + +typedef struct { + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; + u_char type[16]; + int silent; +} ngx_rtmp_publish_t; + + +typedef struct { + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; + double start; + double duration; + int reset; + int silent; +} ngx_rtmp_play_t; + + +typedef struct { + double offset; +} ngx_rtmp_seek_t; + + +typedef struct { + uint8_t pause; + double position; +} ngx_rtmp_pause_t; + + +typedef struct { + uint32_t msid; +} ngx_rtmp_msid_t; + + +typedef ngx_rtmp_msid_t ngx_rtmp_stream_begin_t; +typedef ngx_rtmp_msid_t ngx_rtmp_stream_eof_t; +typedef ngx_rtmp_msid_t ngx_rtmp_stream_dry_t; +typedef ngx_rtmp_msid_t ngx_rtmp_recorded_t; + + +typedef struct { + uint32_t msid; + uint32_t buflen; +} ngx_rtmp_set_buflen_t; + + +void ngx_rtmp_cmd_fill_args(u_char name[NGX_RTMP_MAX_NAME], + u_char args[NGX_RTMP_MAX_ARGS]); + + +typedef ngx_int_t (*ngx_rtmp_connect_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_connect_t *v); +typedef ngx_int_t (*ngx_rtmp_disconnect_pt)(ngx_rtmp_session_t *s); +typedef ngx_int_t (*ngx_rtmp_create_stream_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_create_stream_t *v); +typedef ngx_int_t (*ngx_rtmp_close_stream_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_close_stream_t *v); +typedef ngx_int_t (*ngx_rtmp_delete_stream_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_delete_stream_t *v); +typedef ngx_int_t (*ngx_rtmp_publish_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_publish_t *v); +typedef ngx_int_t (*ngx_rtmp_play_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_play_t *v); +typedef ngx_int_t (*ngx_rtmp_seek_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_seek_t *v); +typedef ngx_int_t (*ngx_rtmp_pause_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_pause_t *v); + +typedef ngx_int_t (*ngx_rtmp_stream_begin_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_stream_begin_t *v); +typedef ngx_int_t (*ngx_rtmp_stream_eof_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_stream_eof_t *v); +typedef ngx_int_t (*ngx_rtmp_stream_dry_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_stream_dry_t *v); +typedef ngx_int_t (*ngx_rtmp_recorded_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_recorded_t *v); +typedef ngx_int_t (*ngx_rtmp_set_buflen_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_set_buflen_t *v); + + +extern ngx_rtmp_connect_pt ngx_rtmp_connect; +extern ngx_rtmp_disconnect_pt ngx_rtmp_disconnect; +extern ngx_rtmp_create_stream_pt ngx_rtmp_create_stream; +extern ngx_rtmp_close_stream_pt ngx_rtmp_close_stream; +extern ngx_rtmp_delete_stream_pt ngx_rtmp_delete_stream; +extern ngx_rtmp_publish_pt ngx_rtmp_publish; +extern ngx_rtmp_play_pt ngx_rtmp_play; +extern ngx_rtmp_seek_pt ngx_rtmp_seek; +extern ngx_rtmp_pause_pt ngx_rtmp_pause; + +extern ngx_rtmp_stream_begin_pt ngx_rtmp_stream_begin; +extern ngx_rtmp_stream_eof_pt ngx_rtmp_stream_eof; +extern ngx_rtmp_stream_dry_pt ngx_rtmp_stream_dry; +extern ngx_rtmp_set_buflen_pt ngx_rtmp_set_buflen; +extern ngx_rtmp_recorded_pt ngx_rtmp_recorded; + + +#endif /*_NGX_RTMP_CMD_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c new file mode 100644 index 0000000..ddc9273 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c @@ -0,0 +1,956 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_codec_module.h" +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_bitop.h" + + +#define NGX_RTMP_CODEC_META_OFF 0 +#define NGX_RTMP_CODEC_META_ON 1 +#define NGX_RTMP_CODEC_META_COPY 2 + + +static void * ngx_rtmp_codec_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_codec_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf); +static ngx_int_t ngx_rtmp_codec_reconstruct_meta(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_codec_copy_meta(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +static ngx_int_t ngx_rtmp_codec_prepare_meta(ngx_rtmp_session_t *s, + uint32_t timestamp); +static void ngx_rtmp_codec_parse_aac_header(ngx_rtmp_session_t *s, + ngx_chain_t *in); +static void ngx_rtmp_codec_parse_avc_header(ngx_rtmp_session_t *s, + ngx_chain_t *in); +#if (NGX_DEBUG) +static void ngx_rtmp_codec_dump_header(ngx_rtmp_session_t *s, const char *type, + ngx_chain_t *in); +#endif + + +typedef struct { + ngx_uint_t meta; +} ngx_rtmp_codec_app_conf_t; + + +static ngx_conf_enum_t ngx_rtmp_codec_meta_slots[] = { + { ngx_string("off"), NGX_RTMP_CODEC_META_OFF }, + { ngx_string("on"), NGX_RTMP_CODEC_META_ON }, + { ngx_string("copy"), NGX_RTMP_CODEC_META_COPY }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_rtmp_codec_commands[] = { + + { ngx_string("meta"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_codec_app_conf_t, meta), + &ngx_rtmp_codec_meta_slots }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_codec_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_codec_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_codec_create_app_conf, /* create app configuration */ + ngx_rtmp_codec_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_codec_module = { + NGX_MODULE_V1, + &ngx_rtmp_codec_module_ctx, /* module context */ + ngx_rtmp_codec_commands, /* module directives */ + NGX_RTMP_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 const char * +audio_codecs[] = { + "", + "ADPCM", + "MP3", + "LinearLE", + "Nellymoser16", + "Nellymoser8", + "Nellymoser", + "G711A", + "G711U", + "", + "AAC", + "Speex", + "", + "", + "MP3-8K", + "DeviceSpecific", + "Uncompressed" +}; + + +static const char * +video_codecs[] = { + "", + "Jpeg", + "Sorenson-H263", + "ScreenVideo", + "On2-VP6", + "On2-VP6-Alpha", + "ScreenVideo2", + "H264", +}; + + +u_char * +ngx_rtmp_get_audio_codec_name(ngx_uint_t id) +{ + return (u_char *)(id < sizeof(audio_codecs) / sizeof(audio_codecs[0]) + ? audio_codecs[id] + : ""); +} + + +u_char * +ngx_rtmp_get_video_codec_name(ngx_uint_t id) +{ + return (u_char *)(id < sizeof(video_codecs) / sizeof(video_codecs[0]) + ? video_codecs[id] + : ""); +} + + +static ngx_uint_t +ngx_rtmp_codec_get_next_version() +{ + ngx_uint_t v; + static ngx_uint_t version; + + do { + v = ++version; + } while (v == 0); + + return v; +} + + +static ngx_int_t +ngx_rtmp_codec_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_codec_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t *cscf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ctx == NULL) { + return NGX_OK; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (ctx->avc_header) { + ngx_rtmp_free_shared_chain(cscf, ctx->avc_header); + ctx->avc_header = NULL; + } + + if (ctx->aac_header) { + ngx_rtmp_free_shared_chain(cscf, ctx->aac_header); + ctx->aac_header = NULL; + } + + if (ctx->meta) { + ngx_rtmp_free_shared_chain(cscf, ctx->meta); + ctx->meta = NULL; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_codec_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_codec_ctx_t *ctx; + ngx_chain_t **header; + uint8_t fmt; + static ngx_uint_t sample_rates[] = + { 5512, 11025, 22050, 44100 }; + + if (h->type != NGX_RTMP_MSG_AUDIO && h->type != NGX_RTMP_MSG_VIDEO) { + return NGX_OK; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t)); + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module); + } + + /* save codec */ + if (in->buf->last - in->buf->pos < 1) { + return NGX_OK; + } + + fmt = in->buf->pos[0]; + if (h->type == NGX_RTMP_MSG_AUDIO) { + ctx->audio_codec_id = (fmt & 0xf0) >> 4; + ctx->audio_channels = (fmt & 0x01) + 1; + ctx->sample_size = (fmt & 0x02) ? 2 : 1; + + if (ctx->sample_rate == 0) { + ctx->sample_rate = sample_rates[(fmt & 0x0c) >> 2]; + } + } else { + ctx->video_codec_id = (fmt & 0x0f); + } + + /* save AVC/AAC header */ + if (in->buf->last - in->buf->pos < 3) { + return NGX_OK; + } + + /* no conf */ + if (!ngx_rtmp_is_codec_header(in)) { + return NGX_OK; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + header = NULL; + + if (h->type == NGX_RTMP_MSG_AUDIO) { + if (ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC) { + header = &ctx->aac_header; + ngx_rtmp_codec_parse_aac_header(s, in); + } + } else { + if (ctx->video_codec_id == NGX_RTMP_VIDEO_H264) { + header = &ctx->avc_header; + ngx_rtmp_codec_parse_avc_header(s, in); + } + } + + if (header == NULL) { + return NGX_OK; + } + + if (*header) { + ngx_rtmp_free_shared_chain(cscf, *header); + } + + *header = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + + return NGX_OK; +} + + +static void +ngx_rtmp_codec_parse_aac_header(ngx_rtmp_session_t *s, ngx_chain_t *in) +{ + ngx_uint_t idx; + ngx_rtmp_codec_ctx_t *ctx; + ngx_rtmp_bit_reader_t br; + + static ngx_uint_t aac_sample_rates[] = + { 96000, 88200, 64000, 48000, + 44100, 32000, 24000, 22050, + 16000, 12000, 11025, 8000, + 7350, 0, 0, 0 }; + +#if (NGX_DEBUG) + ngx_rtmp_codec_dump_header(s, "aac", in); +#endif + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + ngx_rtmp_bit_init_reader(&br, in->buf->pos, in->buf->last); + + ngx_rtmp_bit_read(&br, 16); + + ctx->aac_profile = (ngx_uint_t) ngx_rtmp_bit_read(&br, 5); + if (ctx->aac_profile == 31) { + ctx->aac_profile = (ngx_uint_t) ngx_rtmp_bit_read(&br, 6) + 32; + } + + idx = (ngx_uint_t) ngx_rtmp_bit_read(&br, 4); + if (idx == 15) { + ctx->sample_rate = (ngx_uint_t) ngx_rtmp_bit_read(&br, 24); + } else { + ctx->sample_rate = aac_sample_rates[idx]; + } + + ctx->aac_chan_conf = (ngx_uint_t) ngx_rtmp_bit_read(&br, 4); + + if (ctx->aac_profile == 5 || ctx->aac_profile == 29) { + + if (ctx->aac_profile == 29) { + ctx->aac_ps = 1; + } + + ctx->aac_sbr = 1; + + idx = (ngx_uint_t) ngx_rtmp_bit_read(&br, 4); + if (idx == 15) { + ctx->sample_rate = (ngx_uint_t) ngx_rtmp_bit_read(&br, 24); + } else { + ctx->sample_rate = aac_sample_rates[idx]; + } + + ctx->aac_profile = (ngx_uint_t) ngx_rtmp_bit_read(&br, 5); + if (ctx->aac_profile == 31) { + ctx->aac_profile = (ngx_uint_t) ngx_rtmp_bit_read(&br, 6) + 32; + } + } + + /* MPEG-4 Audio Specific Config + + 5 bits: object type + if (object type == 31) + 6 bits + 32: object type + 4 bits: frequency index + if (frequency index == 15) + 24 bits: frequency + 4 bits: channel configuration + + if (object_type == 5) + 4 bits: frequency index + if (frequency index == 15) + 24 bits: frequency + 5 bits: object type + if (object type == 31) + 6 bits + 32: object type + + var bits: AOT Specific Config + */ + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: aac header profile=%ui, " + "sample_rate=%ui, chan_conf=%ui", + ctx->aac_profile, ctx->sample_rate, ctx->aac_chan_conf); +} + + +static void +ngx_rtmp_codec_parse_avc_header(ngx_rtmp_session_t *s, ngx_chain_t *in) +{ + ngx_uint_t profile_idc, width, height, crop_left, crop_right, + crop_top, crop_bottom, frame_mbs_only, n, cf_idc, + num_ref_frames; + ngx_rtmp_codec_ctx_t *ctx; + ngx_rtmp_bit_reader_t br; + +#if (NGX_DEBUG) + ngx_rtmp_codec_dump_header(s, "avc", in); +#endif + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + ngx_rtmp_bit_init_reader(&br, in->buf->pos, in->buf->last); + + ngx_rtmp_bit_read(&br, 48); + + ctx->avc_profile = (ngx_uint_t) ngx_rtmp_bit_read_8(&br); + ctx->avc_compat = (ngx_uint_t) ngx_rtmp_bit_read_8(&br); + ctx->avc_level = (ngx_uint_t) ngx_rtmp_bit_read_8(&br); + + /* nal bytes */ + ctx->avc_nal_bytes = (ngx_uint_t) ((ngx_rtmp_bit_read_8(&br) & 0x03) + 1); + + /* nnals */ + if ((ngx_rtmp_bit_read_8(&br) & 0x1f) == 0) { + return; + } + + /* nal size */ + ngx_rtmp_bit_read(&br, 16); + + /* nal type */ + if (ngx_rtmp_bit_read_8(&br) != 0x67) { + return; + } + + /* SPS */ + + /* profile idc */ + profile_idc = (ngx_uint_t) ngx_rtmp_bit_read(&br, 8); + + /* flags */ + ngx_rtmp_bit_read(&br, 8); + + /* level idc */ + ngx_rtmp_bit_read(&br, 8); + + /* SPS id */ + ngx_rtmp_bit_read_golomb(&br); + + if (profile_idc == 100 || profile_idc == 110 || + profile_idc == 122 || profile_idc == 244 || profile_idc == 44 || + profile_idc == 83 || profile_idc == 86 || profile_idc == 118) + { + /* chroma format idc */ + cf_idc = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + + if (cf_idc == 3) { + + /* separate color plane */ + ngx_rtmp_bit_read(&br, 1); + } + + /* bit depth luma - 8 */ + ngx_rtmp_bit_read_golomb(&br); + + /* bit depth chroma - 8 */ + ngx_rtmp_bit_read_golomb(&br); + + /* qpprime y zero transform bypass */ + ngx_rtmp_bit_read(&br, 1); + + /* seq scaling matrix present */ + if (ngx_rtmp_bit_read(&br, 1)) { + + for (n = 0; n < (cf_idc != 3 ? 8u : 12u); n++) { + + /* seq scaling list present */ + if (ngx_rtmp_bit_read(&br, 1)) { + + /* TODO: scaling_list() + if (n < 6) { + } else { + } + */ + } + } + } + } + + /* log2 max frame num */ + ngx_rtmp_bit_read_golomb(&br); + + /* pic order cnt type */ + switch (ngx_rtmp_bit_read_golomb(&br)) { + case 0: + + /* max pic order cnt */ + ngx_rtmp_bit_read_golomb(&br); + break; + + case 1: + + /* delta pic order alwys zero */ + ngx_rtmp_bit_read(&br, 1); + + /* offset for non-ref pic */ + ngx_rtmp_bit_read_golomb(&br); + + /* offset for top to bottom field */ + ngx_rtmp_bit_read_golomb(&br); + + /* num ref frames in pic order */ + num_ref_frames = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + + for (n = 0; n < num_ref_frames; n++) { + + /* offset for ref frame */ + ngx_rtmp_bit_read_golomb(&br); + } + } + + /* num ref frames */ + ctx->avc_ref_frames = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + + /* gaps in frame num allowed */ + ngx_rtmp_bit_read(&br, 1); + + /* pic width in mbs - 1 */ + width = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + + /* pic height in map units - 1 */ + height = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + + /* frame mbs only flag */ + frame_mbs_only = (ngx_uint_t) ngx_rtmp_bit_read(&br, 1); + + if (!frame_mbs_only) { + + /* mbs adaprive frame field */ + ngx_rtmp_bit_read(&br, 1); + } + + /* direct 8x8 inference flag */ + ngx_rtmp_bit_read(&br, 1); + + /* frame cropping */ + if (ngx_rtmp_bit_read(&br, 1)) { + + crop_left = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + crop_right = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + crop_top = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + crop_bottom = (ngx_uint_t) ngx_rtmp_bit_read_golomb(&br); + + } else { + + crop_left = 0; + crop_right = 0; + crop_top = 0; + crop_bottom = 0; + } + + ctx->width = (width + 1) * 16 - (crop_left + crop_right) * 2; + ctx->height = (2 - frame_mbs_only) * (height + 1) * 16 - + (crop_top + crop_bottom) * 2; + + ngx_log_debug7(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: avc header " + "profile=%ui, compat=%ui, level=%ui, " + "nal_bytes=%ui, ref_frames=%ui, width=%ui, height=%ui", + ctx->avc_profile, ctx->avc_compat, ctx->avc_level, + ctx->avc_nal_bytes, ctx->avc_ref_frames, + ctx->width, ctx->height); +} + + +#if (NGX_DEBUG) +static void +ngx_rtmp_codec_dump_header(ngx_rtmp_session_t *s, const char *type, + ngx_chain_t *in) +{ + u_char buf[256], *p, *pp; + u_char hex[] = "0123456789abcdef"; + + for (pp = buf, p = in->buf->pos; + p < in->buf->last && pp < buf + sizeof(buf) - 1; + ++p) + { + *pp++ = hex[*p >> 4]; + *pp++ = hex[*p & 0x0f]; + } + + *pp = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: %s header %s", type, buf); +} +#endif + + +static ngx_int_t +ngx_rtmp_codec_reconstruct_meta(ngx_rtmp_session_t *s) +{ + ngx_rtmp_codec_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_int_t rc; + + static struct { + double width; + double height; + double duration; + double frame_rate; + double video_data_rate; + double video_codec_id; + double audio_data_rate; + double audio_codec_id; + u_char profile[32]; + u_char level[32]; + } v; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("Server"), + "NGINX RTMP (github.com/arut/nginx-rtmp-module)", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("width"), + &v.width, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("height"), + &v.height, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("displayWidth"), + &v.width, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("displayHeight"), + &v.height, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("duration"), + &v.duration, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("framerate"), + &v.frame_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("fps"), + &v.frame_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videodatarate"), + &v.video_data_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videocodecid"), + &v.video_codec_id, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiodatarate"), + &v.audio_data_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiocodecid"), + &v.audio_codec_id, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("profile"), + &v.profile, sizeof(v.profile) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + &v.level, sizeof(v.level) }, + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onMetaData", 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, sizeof(out_inf) }, + }; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ctx == NULL) { + return NGX_OK; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (ctx->meta) { + ngx_rtmp_free_shared_chain(cscf, ctx->meta); + ctx->meta = NULL; + } + + v.width = ctx->width; + v.height = ctx->height; + v.duration = ctx->duration; + v.frame_rate = ctx->frame_rate; + v.video_data_rate = ctx->video_data_rate; + v.video_codec_id = ctx->video_codec_id; + v.audio_data_rate = ctx->audio_data_rate; + v.audio_codec_id = ctx->audio_codec_id; + ngx_memcpy(v.profile, ctx->profile, sizeof(ctx->profile)); + ngx_memcpy(v.level, ctx->level, sizeof(ctx->level)); + + rc = ngx_rtmp_append_amf(s, &ctx->meta, NULL, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); + if (rc != NGX_OK || ctx->meta == NULL) { + return NGX_ERROR; + } + + return ngx_rtmp_codec_prepare_meta(s, 0); +} + + +static ngx_int_t +ngx_rtmp_codec_copy_meta(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_codec_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t *cscf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (ctx->meta) { + ngx_rtmp_free_shared_chain(cscf, ctx->meta); + } + + ctx->meta = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + + if (ctx->meta == NULL) { + return NGX_ERROR; + } + + return ngx_rtmp_codec_prepare_meta(s, h->timestamp); +} + + +static ngx_int_t +ngx_rtmp_codec_prepare_meta(ngx_rtmp_session_t *s, uint32_t timestamp) +{ + ngx_rtmp_header_t h; + ngx_rtmp_codec_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + h.type = NGX_RTMP_MSG_AMF_META; + h.timestamp = timestamp; + ngx_rtmp_prepare_message(s, &h, NULL, ctx->meta); + + ctx->meta_version = ngx_rtmp_codec_get_next_version(); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_codec_meta_data(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_codec_app_conf_t *cacf; + ngx_rtmp_codec_ctx_t *ctx; + ngx_uint_t skip; + + static struct { + double width; + double height; + double duration; + double frame_rate; + double video_data_rate; + double video_codec_id_n; + u_char video_codec_id_s[32]; + double audio_data_rate; + double audio_codec_id_n; + u_char audio_codec_id_s[32]; + u_char profile[32]; + u_char level[32]; + } v; + + static ngx_rtmp_amf_elt_t in_video_codec_id[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.video_codec_id_n, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + &v.video_codec_id_s, sizeof(v.video_codec_id_s) }, + }; + + static ngx_rtmp_amf_elt_t in_audio_codec_id[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.audio_codec_id_n, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + &v.audio_codec_id_s, sizeof(v.audio_codec_id_s) }, + }; + + static ngx_rtmp_amf_elt_t in_inf[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_string("width"), + &v.width, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("height"), + &v.height, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("duration"), + &v.duration, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("framerate"), + &v.frame_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("fps"), + &v.frame_rate, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videodatarate"), + &v.video_data_rate, 0 }, + + { NGX_RTMP_AMF_VARIANT, + ngx_string("videocodecid"), + in_video_codec_id, sizeof(in_video_codec_id) }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiodatarate"), + &v.audio_data_rate, 0 }, + + { NGX_RTMP_AMF_VARIANT, + ngx_string("audiocodecid"), + in_audio_codec_id, sizeof(in_audio_codec_id) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("profile"), + &v.profile, sizeof(v.profile) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + &v.level, sizeof(v.level) }, + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_codec_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_codec_ctx_t)); + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_codec_module); + } + + ngx_memzero(&v, sizeof(v)); + + /* use -1 as a sign of unchanged data; + * 0 is a valid value for uncompressed audio */ + v.audio_codec_id_n = -1; + + /* FFmpeg sends a string in front of actal metadata; ignore it */ + skip = !(in->buf->last > in->buf->pos + && *in->buf->pos == NGX_RTMP_AMF_STRING); + if (ngx_rtmp_receive_amf(s, in, in_elts + skip, + sizeof(in_elts) / sizeof(in_elts[0]) - skip)) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "codec: error parsing data frame"); + return NGX_OK; + } + + ctx->width = (ngx_uint_t) v.width; + ctx->height = (ngx_uint_t) v.height; + ctx->duration = (ngx_uint_t) v.duration; + ctx->frame_rate = (ngx_uint_t) v.frame_rate; + ctx->video_data_rate = (ngx_uint_t) v.video_data_rate; + ctx->video_codec_id = (ngx_uint_t) v.video_codec_id_n; + ctx->audio_data_rate = (ngx_uint_t) v.audio_data_rate; + ctx->audio_codec_id = (v.audio_codec_id_n == -1 + ? 0 : v.audio_codec_id_n == 0 + ? NGX_RTMP_AUDIO_UNCOMPRESSED : (ngx_uint_t) v.audio_codec_id_n); + ngx_memcpy(ctx->profile, v.profile, sizeof(v.profile)); + ngx_memcpy(ctx->level, v.level, sizeof(v.level)); + + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "codec: data frame: " + "width=%ui height=%ui duration=%ui frame_rate=%ui " + "video=%s (%ui) audio=%s (%ui)", + ctx->width, ctx->height, ctx->duration, ctx->frame_rate, + ngx_rtmp_get_video_codec_name(ctx->video_codec_id), + ctx->video_codec_id, + ngx_rtmp_get_audio_codec_name(ctx->audio_codec_id), + ctx->audio_codec_id); + + switch (cacf->meta) { + case NGX_RTMP_CODEC_META_ON: + return ngx_rtmp_codec_reconstruct_meta(s); + case NGX_RTMP_CODEC_META_COPY: + return ngx_rtmp_codec_copy_meta(s, h, in); + } + + /* NGX_RTMP_CODEC_META_OFF */ + + return NGX_OK; +} + + +static void * +ngx_rtmp_codec_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_codec_app_conf_t *cacf; + + cacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_codec_app_conf_t)); + if (cacf == NULL) { + return NULL; + } + + cacf->meta = NGX_CONF_UNSET_UINT; + + return cacf; +} + + +static char * +ngx_rtmp_codec_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_codec_app_conf_t *prev = parent; + ngx_rtmp_codec_app_conf_t *conf = child; + + ngx_conf_merge_uint_value(conf->meta, prev->meta, NGX_RTMP_CODEC_META_ON); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_codec_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + ngx_rtmp_amf_handler_t *ch; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]); + *h = ngx_rtmp_codec_av; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]); + *h = ngx_rtmp_codec_av; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); + *h = ngx_rtmp_codec_disconnect; + + /* register metadata handler */ + ch = ngx_array_push(&cmcf->amf); + if (ch == NULL) { + return NGX_ERROR; + } + ngx_str_set(&ch->name, "@setDataFrame"); + ch->handler = ngx_rtmp_codec_meta_data; + + ch = ngx_array_push(&cmcf->amf); + if (ch == NULL) { + return NGX_ERROR; + } + ngx_str_set(&ch->name, "onMetaData"); + ch->handler = ngx_rtmp_codec_meta_data; + + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h new file mode 100644 index 0000000..ee48c1c --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h @@ -0,0 +1,87 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_CODEC_H_INCLUDED_ +#define _NGX_RTMP_CODEC_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +/* Audio codecs */ +enum { + /* Uncompressed codec id is actually 0, + * but we use another value for consistency */ + NGX_RTMP_AUDIO_UNCOMPRESSED = 16, + NGX_RTMP_AUDIO_ADPCM = 1, + NGX_RTMP_AUDIO_MP3 = 2, + NGX_RTMP_AUDIO_LINEAR_LE = 3, + NGX_RTMP_AUDIO_NELLY16 = 4, + NGX_RTMP_AUDIO_NELLY8 = 5, + NGX_RTMP_AUDIO_NELLY = 6, + NGX_RTMP_AUDIO_G711A = 7, + NGX_RTMP_AUDIO_G711U = 8, + NGX_RTMP_AUDIO_AAC = 10, + NGX_RTMP_AUDIO_SPEEX = 11, + NGX_RTMP_AUDIO_MP3_8 = 14, + NGX_RTMP_AUDIO_DEVSPEC = 15, +}; + + +/* Video codecs */ +enum { + NGX_RTMP_VIDEO_JPEG = 1, + NGX_RTMP_VIDEO_SORENSON_H263 = 2, + NGX_RTMP_VIDEO_SCREEN = 3, + NGX_RTMP_VIDEO_ON2_VP6 = 4, + NGX_RTMP_VIDEO_ON2_VP6_ALPHA = 5, + NGX_RTMP_VIDEO_SCREEN2 = 6, + NGX_RTMP_VIDEO_H264 = 7 +}; + + +u_char * ngx_rtmp_get_audio_codec_name(ngx_uint_t id); +u_char * ngx_rtmp_get_video_codec_name(ngx_uint_t id); + + +typedef struct { + ngx_uint_t width; + ngx_uint_t height; + ngx_uint_t duration; + ngx_uint_t frame_rate; + ngx_uint_t video_data_rate; + ngx_uint_t video_codec_id; + ngx_uint_t audio_data_rate; + ngx_uint_t audio_codec_id; + ngx_uint_t aac_profile; + ngx_uint_t aac_chan_conf; + ngx_uint_t aac_sbr; + ngx_uint_t aac_ps; + ngx_uint_t avc_profile; + ngx_uint_t avc_compat; + ngx_uint_t avc_level; + ngx_uint_t avc_nal_bytes; + ngx_uint_t avc_ref_frames; + ngx_uint_t sample_rate; /* 5512, 11025, 22050, 44100 */ + ngx_uint_t sample_size; /* 1=8bit, 2=16bit */ + ngx_uint_t audio_channels; /* 1, 2 */ + u_char profile[32]; + u_char level[32]; + + ngx_chain_t *avc_header; + ngx_chain_t *aac_header; + + ngx_chain_t *meta; + ngx_uint_t meta_version; +} ngx_rtmp_codec_ctx_t; + + +extern ngx_module_t ngx_rtmp_codec_module; + + +#endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_control_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_control_module.c new file mode 100644 index 0000000..adf3ddc --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_control_module.c @@ -0,0 +1,732 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_record_module.h" + + +static char *ngx_rtmp_control(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void * ngx_rtmp_control_create_loc_conf(ngx_conf_t *cf); +static char * ngx_rtmp_control_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +typedef const char * (*ngx_rtmp_control_handler_t)(ngx_http_request_t *r, + ngx_rtmp_session_t *); + + +#define NGX_RTMP_CONTROL_ALL 0xff +#define NGX_RTMP_CONTROL_RECORD 0x01 +#define NGX_RTMP_CONTROL_DROP 0x02 +#define NGX_RTMP_CONTROL_REDIRECT 0x04 + + +enum { + NGX_RTMP_CONTROL_FILTER_CLIENT = 0, + NGX_RTMP_CONTROL_FILTER_PUBLISHER, + NGX_RTMP_CONTROL_FILTER_SUBSCRIBER +}; + + +typedef struct { + ngx_uint_t count; + ngx_str_t path; + ngx_uint_t filter; + ngx_str_t method; + ngx_array_t sessions; /* ngx_rtmp_session_t * */ +} ngx_rtmp_control_ctx_t; + + +typedef struct { + ngx_uint_t control; +} ngx_rtmp_control_loc_conf_t; + + +static ngx_conf_bitmask_t ngx_rtmp_control_masks[] = { + { ngx_string("all"), NGX_RTMP_CONTROL_ALL }, + { ngx_string("record"), NGX_RTMP_CONTROL_RECORD }, + { ngx_string("drop"), NGX_RTMP_CONTROL_DROP }, + { ngx_string("redirect"), NGX_RTMP_CONTROL_REDIRECT }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_rtmp_control_commands[] = { + + { ngx_string("rtmp_control"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_rtmp_control, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_rtmp_control_loc_conf_t, control), + ngx_rtmp_control_masks }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_rtmp_control_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_rtmp_control_create_loc_conf, /* create location configuration */ + ngx_rtmp_control_merge_loc_conf, /* merge location configuration */ +}; + + +ngx_module_t ngx_rtmp_control_module = { + NGX_MODULE_V1, + &ngx_rtmp_control_module_ctx, /* module context */ + ngx_rtmp_control_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 const char * +ngx_rtmp_control_record_handler(ngx_http_request_t *r, ngx_rtmp_session_t *s) +{ + ngx_int_t rc; + ngx_str_t rec; + ngx_uint_t rn; + ngx_rtmp_control_ctx_t *ctx; + ngx_rtmp_core_app_conf_t *cacf; + ngx_rtmp_record_app_conf_t *racf; + + cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module); + racf = cacf->app_conf[ngx_rtmp_record_module.ctx_index]; + + if (ngx_http_arg(r, (u_char *) "rec", sizeof("rec") - 1, &rec) != NGX_OK) { + rec.len = 0; + } + + rn = ngx_rtmp_record_find(racf, &rec); + if (rn == NGX_CONF_UNSET_UINT) { + return "Recorder not found"; + } + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + + if (ctx->method.len == sizeof("start") - 1 && + ngx_strncmp(ctx->method.data, "start", ctx->method.len) == 0) + { + rc = ngx_rtmp_record_open(s, rn, &ctx->path); + + } else if (ctx->method.len == sizeof("stop") - 1 && + ngx_strncmp(ctx->method.data, "stop", ctx->method.len) == 0) + { + rc = ngx_rtmp_record_close(s, rn, &ctx->path); + + } else { + return "Undefined method"; + } + + if (rc == NGX_ERROR) { + return "Recorder error"; + } + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_drop_handler(ngx_http_request_t *r, ngx_rtmp_session_t *s) +{ + ngx_rtmp_control_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + + ngx_rtmp_finalize_session(s); + + ++ctx->count; + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_redirect_handler(ngx_http_request_t *r, ngx_rtmp_session_t *s) +{ + ngx_str_t name; + ngx_rtmp_play_t vplay; + ngx_rtmp_publish_t vpublish; + ngx_rtmp_live_ctx_t *lctx; + ngx_rtmp_control_ctx_t *ctx; + ngx_rtmp_close_stream_t vc; + + if (ngx_http_arg(r, (u_char *) "newname", sizeof("newname") - 1, &name) + != NGX_OK) + { + return "newname not specified"; + } + + if (name.len >= NGX_RTMP_MAX_NAME) { + name.len = NGX_RTMP_MAX_NAME - 1; + } + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + ctx->count++; + + ngx_memzero(&vc, sizeof(ngx_rtmp_close_stream_t)); + + /* close_stream should be synchronous */ + ngx_rtmp_close_stream(s, &vc); + + lctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + + if (lctx && lctx->publishing) { + /* publish */ + + ngx_memzero(&vpublish, sizeof(ngx_rtmp_publish_t)); + + ngx_memcpy(vpublish.name, name.data, name.len); + + ngx_rtmp_cmd_fill_args(vpublish.name, vpublish.args); + + if (ngx_rtmp_publish(s, &vpublish) != NGX_OK) { + return "publish failed"; + } + + } else { + /* play */ + + ngx_memzero(&vplay, sizeof(ngx_rtmp_play_t)); + + ngx_memcpy(vplay.name, name.data, name.len); + + ngx_rtmp_cmd_fill_args(vplay.name, vplay.args); + + if (ngx_rtmp_play(s, &vplay) != NGX_OK) { + return "play failed"; + } + } + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_walk_session(ngx_http_request_t *r, + ngx_rtmp_live_ctx_t *lctx) +{ + ngx_str_t addr, *paddr, clientid; + ngx_rtmp_session_t *s, **ss; + ngx_rtmp_control_ctx_t *ctx; + + s = lctx->session; + + if (s == NULL || s->connection == NULL) { + return NGX_CONF_OK; + } + + if (ngx_http_arg(r, (u_char *) "addr", sizeof("addr") - 1, &addr) + == NGX_OK) + { + paddr = &s->connection->addr_text; + if (paddr->len != addr.len || + ngx_strncmp(paddr->data, addr.data, addr.len)) + { + return NGX_CONF_OK; + } + } + + if (ngx_http_arg(r, (u_char *) "clientid", sizeof("clientid") - 1, + &clientid) + == NGX_OK) + { + if (s->connection->number != + (ngx_uint_t) ngx_atoi(clientid.data, clientid.len)) + { + return NGX_CONF_OK; + } + } + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + + switch (ctx->filter) { + case NGX_RTMP_CONTROL_FILTER_PUBLISHER: + if (!lctx->publishing) { + return NGX_CONF_OK; + } + break; + + case NGX_RTMP_CONTROL_FILTER_SUBSCRIBER: + if (lctx->publishing) { + return NGX_CONF_OK; + } + break; + + case NGX_RTMP_CONTROL_FILTER_CLIENT: + break; + } + + ss = ngx_array_push(&ctx->sessions); + if (ss == NULL) { + return "allocation error"; + } + + *ss = s; + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_walk_stream(ngx_http_request_t *r, + ngx_rtmp_live_stream_t *ls) +{ + const char *s; + ngx_rtmp_live_ctx_t *lctx; + + for (lctx = ls->ctx; lctx; lctx = lctx->next) { + s = ngx_rtmp_control_walk_session(r, lctx); + if (s != NGX_CONF_OK) { + return s; + } + } + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_walk_app(ngx_http_request_t *r, + ngx_rtmp_core_app_conf_t *cacf) +{ + size_t len; + ngx_str_t name; + const char *s; + ngx_uint_t n; + ngx_rtmp_live_stream_t *ls; + ngx_rtmp_live_app_conf_t *lacf; + + lacf = cacf->app_conf[ngx_rtmp_live_module.ctx_index]; + + if (ngx_http_arg(r, (u_char *) "name", sizeof("name") - 1, &name) != NGX_OK) + { + for (n = 0; n < (ngx_uint_t) lacf->nbuckets; ++n) { + for (ls = lacf->streams[n]; ls; ls = ls->next) { + s = ngx_rtmp_control_walk_stream(r, ls); + if (s != NGX_CONF_OK) { + return s; + } + } + } + + return NGX_CONF_OK; + } + + for (ls = lacf->streams[ngx_hash_key(name.data, name.len) % lacf->nbuckets]; + ls; ls = ls->next) + { + len = ngx_strlen(ls->name); + if (name.len != len || ngx_strncmp(name.data, ls->name, name.len)) { + continue; + } + + s = ngx_rtmp_control_walk_stream(r, ls); + if (s != NGX_CONF_OK) { + return s; + } + } + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_walk_server(ngx_http_request_t *r, + ngx_rtmp_core_srv_conf_t *cscf) +{ + ngx_str_t app; + ngx_uint_t n; + const char *s; + ngx_rtmp_core_app_conf_t **pcacf; + + if (ngx_http_arg(r, (u_char *) "app", sizeof("app") - 1, &app) != NGX_OK) { + app.len = 0; + } + + pcacf = cscf->applications.elts; + + for (n = 0; n < cscf->applications.nelts; ++n, ++pcacf) { + if (app.len && ((*pcacf)->name.len != app.len || + ngx_strncmp((*pcacf)->name.data, app.data, app.len))) + { + continue; + } + + s = ngx_rtmp_control_walk_app(r, *pcacf); + if (s != NGX_CONF_OK) { + return s; + } + } + + return NGX_CONF_OK; +} + + +static const char * +ngx_rtmp_control_walk(ngx_http_request_t *r, ngx_rtmp_control_handler_t h) +{ + ngx_rtmp_core_main_conf_t *cmcf = ngx_rtmp_core_main_conf; + + ngx_str_t srv; + ngx_uint_t sn, n; + const char *msg; + ngx_rtmp_session_t **s; + ngx_rtmp_control_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t **pcscf; + + sn = 0; + if (ngx_http_arg(r, (u_char *) "srv", sizeof("srv") - 1, &srv) == NGX_OK) { + sn = ngx_atoi(srv.data, srv.len); + } + + if (sn >= cmcf->servers.nelts) { + return "Server index out of range"; + } + + pcscf = cmcf->servers.elts; + pcscf += sn; + + msg = ngx_rtmp_control_walk_server(r, *pcscf); + if (msg != NGX_CONF_OK) { + return msg; + } + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + + s = ctx->sessions.elts; + for (n = 0; n < ctx->sessions.nelts; n++) { + msg = h(r, s[n]); + if (msg != NGX_CONF_OK) { + return msg; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_control_record(ngx_http_request_t *r, ngx_str_t *method) +{ + ngx_buf_t *b; + const char *msg; + ngx_chain_t cl; + ngx_rtmp_control_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + ctx->filter = NGX_RTMP_CONTROL_FILTER_PUBLISHER; + + msg = ngx_rtmp_control_walk(r, ngx_rtmp_control_record_handler); + if (msg != NGX_CONF_OK) { + goto error; + } + + if (ctx->path.len == 0) { + return NGX_HTTP_NO_CONTENT; + } + + /* output record path */ + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = ctx->path.len; + + b = ngx_create_temp_buf(r->pool, ctx->path.len); + if (b == NULL) { + goto error; + } + + ngx_memzero(&cl, sizeof(cl)); + cl.buf = b; + + b->last = ngx_cpymem(b->pos, ctx->path.data, ctx->path.len); + b->last_buf = 1; + + ngx_http_send_header(r); + + return ngx_http_output_filter(r, &cl); + +error: + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static ngx_int_t +ngx_rtmp_control_drop(ngx_http_request_t *r, ngx_str_t *method) +{ + size_t len; + u_char *p; + ngx_buf_t *b; + ngx_chain_t cl; + const char *msg; + ngx_rtmp_control_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + + if (ctx->method.len == sizeof("publisher") - 1 && + ngx_memcmp(ctx->method.data, "publisher", ctx->method.len) == 0) + { + ctx->filter = NGX_RTMP_CONTROL_FILTER_PUBLISHER; + + } else if (ctx->method.len == sizeof("subscriber") - 1 && + ngx_memcmp(ctx->method.data, "subscriber", ctx->method.len) + == 0) + { + ctx->filter = NGX_RTMP_CONTROL_FILTER_SUBSCRIBER; + + } else if (method->len == sizeof("client") - 1 && + ngx_memcmp(ctx->method.data, "client", ctx->method.len) == 0) + { + ctx->filter = NGX_RTMP_CONTROL_FILTER_CLIENT; + + } else { + msg = "Undefined filter"; + goto error; + } + + msg = ngx_rtmp_control_walk(r, ngx_rtmp_control_drop_handler); + if (msg != NGX_CONF_OK) { + goto error; + } + + /* output count */ + + len = NGX_INT_T_LEN; + + p = ngx_palloc(r->connection->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + len = (size_t) (ngx_snprintf(p, len, "%ui", ctx->count) - p); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = len; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + goto error; + } + + b->start = b->pos = p; + b->end = b->last = p + len; + b->temporary = 1; + b->last_buf = 1; + + ngx_memzero(&cl, sizeof(cl)); + cl.buf = b; + + ngx_http_send_header(r); + + return ngx_http_output_filter(r, &cl); + +error: + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static ngx_int_t +ngx_rtmp_control_redirect(ngx_http_request_t *r, ngx_str_t *method) +{ + size_t len; + u_char *p; + ngx_buf_t *b; + ngx_chain_t cl; + const char *msg; + ngx_rtmp_control_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_rtmp_control_module); + + if (ctx->method.len == sizeof("publisher") - 1 && + ngx_memcmp(ctx->method.data, "publisher", ctx->method.len) == 0) + { + ctx->filter = NGX_RTMP_CONTROL_FILTER_PUBLISHER; + + } else if (ctx->method.len == sizeof("subscriber") - 1 && + ngx_memcmp(ctx->method.data, "subscriber", ctx->method.len) + == 0) + { + ctx->filter = NGX_RTMP_CONTROL_FILTER_SUBSCRIBER; + + } else if (ctx->method.len == sizeof("client") - 1 && + ngx_memcmp(ctx->method.data, "client", ctx->method.len) == 0) + { + ctx->filter = NGX_RTMP_CONTROL_FILTER_CLIENT; + + } else { + msg = "Undefined filter"; + goto error; + } + + msg = ngx_rtmp_control_walk(r, ngx_rtmp_control_redirect_handler); + if (msg != NGX_CONF_OK) { + goto error; + } + + /* output count */ + + len = NGX_INT_T_LEN; + + p = ngx_palloc(r->connection->pool, len); + if (p == NULL) { + goto error; + } + + len = (size_t) (ngx_snprintf(p, len, "%ui", ctx->count) - p); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = len; + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + goto error; + } + + b->start = b->pos = p; + b->end = b->last = p + len; + b->temporary = 1; + b->last_buf = 1; + + ngx_memzero(&cl, sizeof(cl)); + cl.buf = b; + + ngx_http_send_header(r); + + return ngx_http_output_filter(r, &cl); + +error: + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static ngx_int_t +ngx_rtmp_control_handler(ngx_http_request_t *r) +{ + u_char *p; + ngx_str_t section, method; + ngx_uint_t n; + ngx_rtmp_control_ctx_t *ctx; + ngx_rtmp_control_loc_conf_t *llcf; + + llcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_control_module); + if (llcf->control == 0) { + return NGX_DECLINED; + } + + /* uri format: .../section/method?args */ + + ngx_str_null(§ion); + ngx_str_null(&method); + + for (n = r->uri.len; n; --n) { + p = &r->uri.data[n - 1]; + + if (*p != '/') { + continue; + } + + if (method.data) { + section.data = p + 1; + section.len = method.data - section.data - 1; + break; + } + + method.data = p + 1; + method.len = r->uri.data + r->uri.len - method.data; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, r->connection->log, 0, + "rtmp_control: section='%V' method='%V'", + §ion, &method); + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_rtmp_control_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_rtmp_control_module); + + if (ngx_array_init(&ctx->sessions, r->pool, 1, sizeof(void *)) != NGX_OK) { + return NGX_ERROR; + } + + ctx->method = method; + +#define NGX_RTMP_CONTROL_SECTION(flag, secname) \ + if (llcf->control & NGX_RTMP_CONTROL_##flag && \ + section.len == sizeof(#secname) - 1 && \ + ngx_strncmp(section.data, #secname, sizeof(#secname) - 1) == 0) \ + { \ + return ngx_rtmp_control_##secname(r, &method); \ + } + + NGX_RTMP_CONTROL_SECTION(RECORD, record); + NGX_RTMP_CONTROL_SECTION(DROP, drop); + NGX_RTMP_CONTROL_SECTION(REDIRECT, redirect); + +#undef NGX_RTMP_CONTROL_SECTION + + return NGX_DECLINED; +} + + +static void * +ngx_rtmp_control_create_loc_conf(ngx_conf_t *cf) +{ + ngx_rtmp_control_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_control_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->control = 0; + + return conf; +} + + +static char * +ngx_rtmp_control_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_control_loc_conf_t *prev = parent; + ngx_rtmp_control_loc_conf_t *conf = child; + + ngx_conf_merge_bitmask_value(conf->control, prev->control, 0); + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_control(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_rtmp_control_handler; + + return ngx_conf_set_bitmask_slot(cf, cmd, conf); +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_core_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_core_module.c new file mode 100644 index 0000000..a33fa16 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_core_module.c @@ -0,0 +1,755 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include +#include "ngx_rtmp.h" + + +static void *ngx_rtmp_core_create_main_conf(ngx_conf_t *cf); +static void *ngx_rtmp_core_create_srv_conf(ngx_conf_t *cf); +static char *ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static void *ngx_rtmp_core_create_app_conf(ngx_conf_t *cf); +static char *ngx_rtmp_core_merge_app_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_rtmp_core_application(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +ngx_rtmp_core_main_conf_t *ngx_rtmp_core_main_conf; + + +static ngx_conf_deprecated_t ngx_conf_deprecated_so_keepalive = { + ngx_conf_deprecated, "so_keepalive", + "so_keepalive\" parameter of the \"listen" +}; + + +static ngx_command_t ngx_rtmp_core_commands[] = { + + { ngx_string("server"), + NGX_RTMP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_rtmp_core_server, + 0, + 0, + NULL }, + + { ngx_string("listen"), + NGX_RTMP_SRV_CONF|NGX_CONF_TAKE12, + ngx_rtmp_core_listen, + NGX_RTMP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("application"), + NGX_RTMP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_rtmp_core_application, + NGX_RTMP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("so_keepalive"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, so_keepalive), + &ngx_conf_deprecated_so_keepalive }, + + { ngx_string("timeout"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, timeout), + NULL }, + + { ngx_string("ping"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, ping), + NULL }, + + { ngx_string("ping_timeout"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, ping_timeout), + NULL }, + + { ngx_string("max_streams"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, max_streams), + NULL }, + + { ngx_string("ack_window"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, ack_window), + NULL }, + + { ngx_string("chunk_size"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, chunk_size), + NULL }, + + { ngx_string("max_message"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, max_message), + NULL }, + + { ngx_string("out_queue"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, out_queue), + NULL }, + + { ngx_string("out_cork"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, out_cork), + NULL }, + + { ngx_string("busy"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, busy), + NULL }, + + /* time fixes are needed for flash clients */ + { ngx_string("play_time_fix"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, play_time_fix), + NULL }, + + { ngx_string("publish_time_fix"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, publish_time_fix), + NULL }, + + { ngx_string("buflen"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_core_srv_conf_t, buflen), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_core_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + ngx_rtmp_core_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + ngx_rtmp_core_create_srv_conf, /* create server configuration */ + ngx_rtmp_core_merge_srv_conf, /* merge server configuration */ + ngx_rtmp_core_create_app_conf, /* create app configuration */ + ngx_rtmp_core_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_core_module = { + NGX_MODULE_V1, + &ngx_rtmp_core_module_ctx, /* module context */ + ngx_rtmp_core_commands, /* module directives */ + NGX_RTMP_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_rtmp_core_create_main_conf(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + + cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_core_main_conf_t)); + if (cmcf == NULL) { + return NULL; + } + + ngx_rtmp_core_main_conf = cmcf; + + if (ngx_array_init(&cmcf->servers, cf->pool, 4, + sizeof(ngx_rtmp_core_srv_conf_t *)) + != NGX_OK) + { + return NULL; + } + + if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_rtmp_listen_t)) + != NGX_OK) + { + return NULL; + } + + return cmcf; +} + + +static void * +ngx_rtmp_core_create_srv_conf(ngx_conf_t *cf) +{ + ngx_rtmp_core_srv_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_core_srv_conf_t)); + if (conf == NULL) { + return NULL; + } + + if (ngx_array_init(&conf->applications, cf->pool, 4, + sizeof(ngx_rtmp_core_app_conf_t *)) + != NGX_OK) + { + return NULL; + } + + conf->timeout = NGX_CONF_UNSET_MSEC; + conf->ping = NGX_CONF_UNSET_MSEC; + conf->ping_timeout = NGX_CONF_UNSET_MSEC; + conf->so_keepalive = NGX_CONF_UNSET; + conf->max_streams = NGX_CONF_UNSET; + conf->chunk_size = NGX_CONF_UNSET; + conf->ack_window = NGX_CONF_UNSET_UINT; + conf->max_message = NGX_CONF_UNSET_SIZE; + conf->out_queue = NGX_CONF_UNSET_SIZE; + conf->out_cork = NGX_CONF_UNSET_SIZE; + conf->play_time_fix = NGX_CONF_UNSET; + conf->publish_time_fix = NGX_CONF_UNSET; + conf->buflen = NGX_CONF_UNSET_MSEC; + conf->busy = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_rtmp_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_core_srv_conf_t *prev = parent; + ngx_rtmp_core_srv_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_msec_value(conf->ping, prev->ping, 60000); + ngx_conf_merge_msec_value(conf->ping_timeout, prev->ping_timeout, 30000); + + ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); + ngx_conf_merge_value(conf->max_streams, prev->max_streams, 32); + ngx_conf_merge_value(conf->chunk_size, prev->chunk_size, 4096); + ngx_conf_merge_uint_value(conf->ack_window, prev->ack_window, 5000000); + ngx_conf_merge_size_value(conf->max_message, prev->max_message, + 1 * 1024 * 1024); + ngx_conf_merge_size_value(conf->out_queue, prev->out_queue, 256); + ngx_conf_merge_size_value(conf->out_cork, prev->out_cork, + conf->out_queue / 8); + ngx_conf_merge_value(conf->play_time_fix, prev->play_time_fix, 1); + ngx_conf_merge_value(conf->publish_time_fix, prev->publish_time_fix, 1); + ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 1000); + ngx_conf_merge_value(conf->busy, prev->busy, 0); + + if (prev->pool == NULL) { + prev->pool = ngx_create_pool(4096, &cf->cycle->new_log); + if (prev->pool == NULL) { + return NGX_CONF_ERROR; + } + } + + conf->pool = prev->pool; + + return NGX_CONF_OK; +} + + +static void * +ngx_rtmp_core_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_core_app_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_core_app_conf_t)); + if (conf == NULL) { + return NULL; + } + + if (ngx_array_init(&conf->applications, cf->pool, 1, + sizeof(ngx_rtmp_core_app_conf_t *)) + != NGX_OK) + { + return NULL; + } + + return conf; +} + + +static char * +ngx_rtmp_core_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_core_app_conf_t *prev = parent; + ngx_rtmp_core_app_conf_t *conf = child; + + (void)prev; + (void)conf; + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + void *mconf; + ngx_uint_t m; + ngx_conf_t pcf; + ngx_module_t **modules; + ngx_rtmp_module_t *module; + ngx_rtmp_conf_ctx_t *ctx, *rtmp_ctx; + ngx_rtmp_core_srv_conf_t *cscf, **cscfp; + ngx_rtmp_core_main_conf_t *cmcf; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + rtmp_ctx = cf->ctx; + ctx->main_conf = rtmp_ctx->main_conf; + + /* the server{}'s srv_conf */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + +#if (nginx_version >= 1009011) + modules = cf->cycle->modules; +#else + modules = ngx_modules; +#endif + + for (m = 0; modules[m]; m++) { + if (modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[m]->ctx; + + if (module->create_srv_conf) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[modules[m]->ctx_index] = mconf; + } + + if (module->create_app_conf) { + mconf = module->create_app_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->app_conf[modules[m]->ctx_index] = mconf; + } + } + + /* the server configuration context */ + + cscf = ctx->srv_conf[ngx_rtmp_core_module.ctx_index]; + cscf->ctx = ctx; + + cmcf = ctx->main_conf[ngx_rtmp_core_module.ctx_index]; + + cscfp = ngx_array_push(&cmcf->servers); + if (cscfp == NULL) { + return NGX_CONF_ERROR; + } + + *cscfp = cscf; + + + /* parse inside server{} */ + + pcf = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_RTMP_SRV_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + return rv; +} + + +static char * +ngx_rtmp_core_application(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_int_t i; + ngx_str_t *value; + ngx_conf_t save; + ngx_module_t **modules; + ngx_rtmp_module_t *module; + ngx_rtmp_conf_ctx_t *ctx, *pctx; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_core_app_conf_t *cacf, **cacfp; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + pctx = cf->ctx; + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + +#if (nginx_version >= 1009011) + modules = cf->cycle->modules; +#else + modules = ngx_modules; +#endif + + for (i = 0; modules[i]; i++) { + if (modules[i]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[i]->ctx; + + if (module->create_app_conf) { + ctx->app_conf[modules[i]->ctx_index] = module->create_app_conf(cf); + if (ctx->app_conf[modules[i]->ctx_index] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + cacf = ctx->app_conf[ngx_rtmp_core_module.ctx_index]; + cacf->app_conf = ctx->app_conf; + + value = cf->args->elts; + + cacf->name = value[1]; + cscf = pctx->srv_conf[ngx_rtmp_core_module.ctx_index]; + + cacfp = ngx_array_push(&cscf->applications); + if (cacfp == NULL) { + return NGX_CONF_ERROR; + } + + *cacfp = cacf; + + save = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_RTMP_APP_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf= save; + + return rv; +} + + +static char * +ngx_rtmp_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + size_t len, off; + in_port_t port; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t i, m; + ngx_module_t **modules; + struct sockaddr *sa; + ngx_rtmp_listen_t *ls; + struct sockaddr_in *sin; + ngx_rtmp_core_main_conf_t *cmcf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + value = cf->args->elts; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.listen = 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 \"listen\" directive", + u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + ls = cmcf->listen.elts; + + for (i = 0; i < cmcf->listen.nelts; i++) { + + sa = (struct sockaddr *) ls[i].sockaddr; + + if (sa->sa_family != u.family) { + continue; + } + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + off = offsetof(struct sockaddr_in6, sin6_addr); + len = 16; + sin6 = (struct sockaddr_in6 *) sa; + port = sin6->sin6_port; + break; +#endif + + default: /* AF_INET */ + off = offsetof(struct sockaddr_in, sin_addr); + len = 4; + sin = (struct sockaddr_in *) sa; + port = sin->sin_port; + break; + } + + if (ngx_memcmp(ls[i].sockaddr + off, (u_char *) &u.sockaddr + off, len) + != 0) + { + continue; + } + + if (port != u.port) { + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"%V\" address and port pair", &u.url); + return NGX_CONF_ERROR; + } + + ls = ngx_array_push(&cmcf->listen); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(ls, sizeof(ngx_rtmp_listen_t)); + + ngx_memcpy(ls->sockaddr, (u_char *) &u.sockaddr, u.socklen); + + ls->socklen = u.socklen; + ls->wildcard = u.wildcard; + ls->ctx = cf->ctx; + +#if (nginx_version >= 1009011) + modules = cf->cycle->modules; +#else + modules = ngx_modules; +#endif + + for (m = 0; modules[m]; m++) { + if (modules[m]->type != NGX_RTMP_MODULE) { + continue; + } + } + + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "bind") == 0) { + ls->bind = 1; + continue; + } + + if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) { +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + struct sockaddr *sa; + u_char buf[NGX_SOCKADDR_STRLEN]; + + sa = (struct sockaddr *) ls->sockaddr; + + if (sa->sa_family == AF_INET6) { + + if (ngx_strcmp(&value[i].data[10], "n") == 0) { + ls->ipv6only = 1; + + } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) { + ls->ipv6only = 0; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid ipv6only flags \"%s\"", + &value[i].data[9]); + return NGX_CONF_ERROR; + } + + ls->bind = 1; + + } else { + len = ngx_sock_ntop(sa, +#if (nginx_version >= 1005003) + ls->socklen, +#endif + buf, NGX_SOCKADDR_STRLEN, 1); + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ipv6only is not supported " + "on addr \"%*s\", ignored", len, buf); + } + + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bind ipv6only is not supported " + "on this platform"); + return NGX_CONF_ERROR; +#endif + } + + if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) { + + if (ngx_strcmp(&value[i].data[13], "on") == 0) { + ls->so_keepalive = 1; + + } else if (ngx_strcmp(&value[i].data[13], "off") == 0) { + ls->so_keepalive = 2; + + } else { + +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + u_char *p, *end; + ngx_str_t s; + + end = value[i].data + value[i].len; + s.data = value[i].data + 13; + + p = ngx_strlchr(s.data, end, ':'); + if (p == NULL) { + p = end; + } + + 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) { + goto invalid_so_keepalive; + } + } + + s.data = (p < end) ? (p + 1) : end; + + p = ngx_strlchr(s.data, end, ':'); + if (p == NULL) { + p = end; + } + + 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) { + goto invalid_so_keepalive; + } + } + + s.data = (p < end) ? (p + 1) : end; + + if (s.data < end) { + s.len = end - s.data; + + ls->tcp_keepcnt = ngx_atoi(s.data, s.len); + if (ls->tcp_keepcnt == NGX_ERROR) { + goto invalid_so_keepalive; + } + } + + if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0 + && ls->tcp_keepcnt == 0) + { + goto invalid_so_keepalive; + } + + ls->so_keepalive = 1; + +#else + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"so_keepalive\" parameter accepts " + "only \"on\" or \"off\" on this platform"); + return NGX_CONF_ERROR; + +#endif + } + + ls->bind = 1; + + continue; + +#if (NGX_HAVE_KEEPALIVE_TUNABLE) + invalid_so_keepalive: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid so_keepalive value: \"%s\"", + &value[i].data[13]); + return NGX_CONF_ERROR; +#endif + } + + if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) { + ls->proxy_protocol = 1; + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the invalid \"%V\" parameter", &value[i]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_eval.c b/debian/modules/nginx-rtmp/ngx_rtmp_eval.c new file mode 100644 index 0000000..24e1f80 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_eval.c @@ -0,0 +1,282 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_eval.h" + + +#define NGX_RTMP_EVAL_BUFLEN 16 + + +static void +ngx_rtmp_eval_session_str(void *ctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) +{ + *ret = *(ngx_str_t *) ((u_char *) ctx + e->offset); +} + + +static void +ngx_rtmp_eval_connection_str(void *ctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) +{ + ngx_rtmp_session_t *s = ctx; + + *ret = *(ngx_str_t *) ((u_char *) s->connection + e->offset); +} + + +ngx_rtmp_eval_t ngx_rtmp_eval_session[] = { + + { ngx_string("app"), + ngx_rtmp_eval_session_str, + offsetof(ngx_rtmp_session_t, app) }, + + { ngx_string("flashver"), + ngx_rtmp_eval_session_str, + offsetof(ngx_rtmp_session_t, flashver) }, + + { ngx_string("swfurl"), + ngx_rtmp_eval_session_str, + offsetof(ngx_rtmp_session_t, swf_url) }, + + { ngx_string("tcurl"), + ngx_rtmp_eval_session_str, + offsetof(ngx_rtmp_session_t, tc_url) }, + + { ngx_string("pageurl"), + ngx_rtmp_eval_session_str, + offsetof(ngx_rtmp_session_t, page_url) }, + + { ngx_string("addr"), + ngx_rtmp_eval_connection_str, + offsetof(ngx_connection_t, addr_text) }, + + ngx_rtmp_null_eval +}; + + +static void +ngx_rtmp_eval_append(ngx_buf_t *b, void *data, size_t len, ngx_log_t *log) +{ + size_t buf_len; + + if (b->last + len > b->end) { + buf_len = 2 * (b->last - b->pos) + len; + + b->start = ngx_alloc(buf_len, log); + if (b->start == NULL) { + return; + } + + b->last = ngx_cpymem(b->start, b->pos, b->last - b->pos); + b->pos = b->start; + b->end = b->start + buf_len; + } + + b->last = ngx_cpymem(b->last, data, len); +} + + +static void +ngx_rtmp_eval_append_var(void *ctx, ngx_buf_t *b, ngx_rtmp_eval_t **e, + ngx_str_t *name, ngx_log_t *log) +{ + ngx_uint_t k; + ngx_str_t v; + ngx_rtmp_eval_t *ee; + + for (; *e; ++e) { + for (k = 0, ee = *e; ee->handler; ++k, ++ee) { + if (ee->name.len == name->len && + ngx_memcmp(ee->name.data, name->data, name->len) == 0) + { + ee->handler(ctx, ee, &v); + ngx_rtmp_eval_append(b, v.data, v.len, log); + } + } + } +} + + +ngx_int_t +ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, ngx_str_t *out, + ngx_log_t *log) +{ + u_char c, *p; + ngx_str_t name; + ngx_buf_t b; + ngx_uint_t n; + + enum { + NORMAL, + ESCAPE, + NAME, + SNAME + } state = NORMAL; + + b.pos = b.last = b.start = ngx_alloc(NGX_RTMP_EVAL_BUFLEN, log); + if (b.pos == NULL) { + return NGX_ERROR; + } + + b.end = b.pos + NGX_RTMP_EVAL_BUFLEN; + name.data = NULL; + + for (n = 0; n < in->len; ++n) { + p = &in->data[n]; + c = *p; + + switch (state) { + case SNAME: + if (c != '}') { + continue; + } + + name.len = p - name.data; + ngx_rtmp_eval_append_var(ctx, &b, e, &name, log); + + state = NORMAL; + + continue; + + case NAME: + if (c == '{' && name.data == p) { + ++name.data; + state = SNAME; + continue; + } + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { + continue; + } + + name.len = p - name.data; + ngx_rtmp_eval_append_var(ctx, &b, e, &name, log); + + case NORMAL: + switch (c) { + case '$': + name.data = p + 1; + state = NAME; + continue; + case '\\': + state = ESCAPE; + continue; + } + + case ESCAPE: + ngx_rtmp_eval_append(&b, &c, 1, log); + state = NORMAL; + break; + + } + } + + if (state == NAME) { + p = &in->data[n]; + name.len = p - name.data; + ngx_rtmp_eval_append_var(ctx, &b, e, &name, log); + } + + c = 0; + ngx_rtmp_eval_append(&b, &c, 1, log); + + out->data = b.pos; + out->len = b.last - b.pos - 1; + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_eval_streams(ngx_str_t *in) +{ +#if !(NGX_WIN32) + ngx_int_t mode, create, v, close_src; + ngx_fd_t dst, src; + u_char *path; + + path = in->data; + + while (*path >= '0' && *path <= '9') { + path++; + } + + switch ((char) *path) { + + case '>': + + v = (path == in->data ? 1 : ngx_atoi(in->data, path - in->data)); + if (v == NGX_ERROR) { + return NGX_ERROR; + } + + dst = (ngx_fd_t) v; + mode = NGX_FILE_WRONLY; + create = NGX_FILE_TRUNCATE; + path++; + + if (*path == (u_char) '>') { + mode = NGX_FILE_APPEND; + create = NGX_FILE_CREATE_OR_OPEN; + path++; + } + + break; + + case '<': + + v = (path == in->data ? 0 : ngx_atoi(in->data, path - in->data)); + if (v == NGX_ERROR) { + return NGX_ERROR; + } + + dst = (ngx_fd_t) v; + mode = NGX_FILE_RDONLY; + create = NGX_FILE_OPEN; + path++; + + break; + + default: + + return NGX_DONE; + } + + if (*path == (u_char) '&') { + + path++; + v = ngx_atoi(path, in->data + in->len - path); + if (v == NGX_ERROR) { + return NGX_ERROR; + } + src = (ngx_fd_t) v; + close_src = 0; + + } else { + + src = ngx_open_file(path, mode, create, NGX_FILE_DEFAULT_ACCESS); + if (src == NGX_INVALID_FILE) { + return NGX_ERROR; + } + close_src = 1; + + } + + if (src == dst) { + return NGX_OK; + } + + dup2(src, dst); + + if (close_src) { + ngx_close_file(src); + } + return NGX_OK; + +#else + return NGX_DONE; +#endif +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_eval.h b/debian/modules/nginx-rtmp/ngx_rtmp_eval.h new file mode 100644 index 0000000..b05d16b --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_eval.h @@ -0,0 +1,44 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_EVAL_H_INCLUDED_ +#define _NGX_RTMP_EVAL_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +typedef struct ngx_rtmp_eval_s ngx_rtmp_eval_t; + + +typedef void (* ngx_rtmp_eval_pt)(void *ctx, ngx_rtmp_eval_t *e, + ngx_str_t *ret); + + +struct ngx_rtmp_eval_s { + ngx_str_t name; + ngx_rtmp_eval_pt handler; + ngx_uint_t offset; +}; + + +#define ngx_rtmp_null_eval { ngx_null_string, NULL, 0 } + + +/* standard session eval variables */ +extern ngx_rtmp_eval_t ngx_rtmp_eval_session[]; + + +ngx_int_t ngx_rtmp_eval(void *ctx, ngx_str_t *in, ngx_rtmp_eval_t **e, + ngx_str_t *out, ngx_log_t *log); + + +ngx_int_t ngx_rtmp_eval_streams(ngx_str_t *in); + + +#endif /* _NGX_RTMP_EVAL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c new file mode 100644 index 0000000..fccd4ba --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c @@ -0,0 +1,1604 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_record_module.h" +#include "ngx_rtmp_eval.h" +#include + +#ifdef NGX_LINUX +#include +#endif + + +#if !(NGX_WIN32) +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_play_pt next_play; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_record_done_pt next_record_done; +#endif + + +static ngx_int_t ngx_rtmp_exec_init_process(ngx_cycle_t *cycle); +static ngx_int_t ngx_rtmp_exec_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_exec_create_main_conf(ngx_conf_t *cf); +static char * ngx_rtmp_exec_init_main_conf(ngx_conf_t *cf, void *conf); +static void * ngx_rtmp_exec_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_exec_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +/*static char * ngx_rtmp_exec_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf);*/ +static char * ngx_rtmp_exec_conf(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_rtmp_exec_kill_signal(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +#define NGX_RTMP_EXEC_RESPAWN 0x01 +#define NGX_RTMP_EXEC_KILL 0x02 + + +#define NGX_RTMP_EXEC_PUBLISHING 0x01 +#define NGX_RTMP_EXEC_PLAYING 0x02 + + +enum { + NGX_RTMP_EXEC_PUSH, + NGX_RTMP_EXEC_PULL, + + NGX_RTMP_EXEC_PUBLISH, + NGX_RTMP_EXEC_PUBLISH_DONE, + NGX_RTMP_EXEC_PLAY, + NGX_RTMP_EXEC_PLAY_DONE, + NGX_RTMP_EXEC_RECORD_DONE, + + NGX_RTMP_EXEC_MAX, + + NGX_RTMP_EXEC_STATIC +}; + + +typedef struct { + ngx_str_t id; + ngx_uint_t type; + ngx_str_t cmd; + ngx_array_t args; /* ngx_str_t */ + ngx_array_t names; +} ngx_rtmp_exec_conf_t; + + +typedef struct { + ngx_rtmp_exec_conf_t *conf; + ngx_log_t *log; + ngx_rtmp_eval_t **eval; + void *eval_ctx; + unsigned active:1; + unsigned managed:1; + ngx_pid_t pid; + ngx_pid_t *save_pid; + int pipefd; + ngx_connection_t dummy_conn; /*needed by ngx_xxx_event*/ + ngx_event_t read_evt, write_evt; + ngx_event_t respawn_evt; + ngx_msec_t respawn_timeout; + ngx_int_t kill_signal; +} ngx_rtmp_exec_t; + + +typedef struct { + ngx_array_t static_conf; /* ngx_rtmp_exec_conf_t */ + ngx_array_t static_exec; /* ngx_rtmp_exec_t */ + ngx_msec_t respawn_timeout; + ngx_int_t kill_signal; + ngx_log_t *log; +} ngx_rtmp_exec_main_conf_t; + + +typedef struct ngx_rtmp_exec_pull_ctx_s ngx_rtmp_exec_pull_ctx_t; + +struct ngx_rtmp_exec_pull_ctx_s { + ngx_pool_t *pool; + ngx_uint_t counter; + ngx_str_t name; + ngx_str_t app; + ngx_array_t pull_exec; /* ngx_rtmp_exec_t */ + ngx_rtmp_exec_pull_ctx_t *next; +}; + + +typedef struct { + ngx_int_t active; + ngx_array_t conf[NGX_RTMP_EXEC_MAX]; + /* ngx_rtmp_exec_conf_t */ + ngx_flag_t respawn; + ngx_flag_t options; + ngx_uint_t nbuckets; + ngx_rtmp_exec_pull_ctx_t **pull; +} ngx_rtmp_exec_app_conf_t; + + +typedef struct { + ngx_uint_t flags; + ngx_str_t path; /* /tmp/rec/myfile-123.flv */ + ngx_str_t filename; /* myfile-123.flv */ + ngx_str_t basename; /* myfile-123 */ + ngx_str_t dirname; /* /tmp/rec */ + ngx_str_t recorder; + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; + ngx_array_t push_exec; /* ngx_rtmp_exec_t */ + ngx_rtmp_exec_pull_ctx_t *pull; +} ngx_rtmp_exec_ctx_t; + + +#if !(NGX_WIN32) +static void ngx_rtmp_exec_respawn(ngx_event_t *ev); +static ngx_int_t ngx_rtmp_exec_kill(ngx_rtmp_exec_t *e, ngx_int_t kill_signal); +static ngx_int_t ngx_rtmp_exec_run(ngx_rtmp_exec_t *e); +#endif + + +static ngx_command_t ngx_rtmp_exec_commands[] = { +/* + { ngx_string("exec_block"), + NGX_RTMP_APP_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS|NGX_CONF_TAKE1, + ngx_rtmp_exec_block, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, +*/ + { ngx_string("exec"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PUSH * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_push"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PUSH * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_pull"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PULL * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_publish"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PUBLISH * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_publish_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PUBLISH_DONE * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_play"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PLAY * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_play_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_PLAY_DONE * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_record_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF| + NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, conf) + + NGX_RTMP_EXEC_RECORD_DONE * sizeof(ngx_array_t), + NULL }, + + { ngx_string("exec_static"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_exec_conf, + NGX_RTMP_MAIN_CONF_OFFSET, + offsetof(ngx_rtmp_exec_main_conf_t, static_conf), + NULL }, + + { ngx_string("respawn"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, respawn), + NULL }, + + { ngx_string("respawn_timeout"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_MAIN_CONF_OFFSET, + offsetof(ngx_rtmp_exec_main_conf_t, respawn_timeout), + NULL }, + + { ngx_string("exec_kill_signal"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_exec_kill_signal, + NGX_RTMP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("exec_options"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_exec_app_conf_t, options), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_exec_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_exec_postconfiguration, /* postconfiguration */ + ngx_rtmp_exec_create_main_conf, /* create main configuration */ + ngx_rtmp_exec_init_main_conf, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_exec_create_app_conf, /* create app configuration */ + ngx_rtmp_exec_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_exec_module = { + NGX_MODULE_V1, + &ngx_rtmp_exec_module_ctx, /* module context */ + ngx_rtmp_exec_commands, /* module directives */ + NGX_RTMP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_rtmp_exec_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static void +ngx_rtmp_exec_eval_ctx_cstr(void *sctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) +{ + ngx_rtmp_session_t *s = sctx; + + ngx_rtmp_exec_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + if (ctx == NULL) { + ret->len = 0; + return; + } + + ret->data = (u_char *) ctx + e->offset; + ret->len = ngx_strlen(ret->data); +} + + +static void +ngx_rtmp_exec_eval_ctx_str(void *sctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) +{ + ngx_rtmp_session_t *s = sctx; + + ngx_rtmp_exec_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + if (ctx == NULL) { + ret->len = 0; + return; + } + + *ret = * (ngx_str_t *) ((u_char *) ctx + e->offset); +} + + +static void +ngx_rtmp_exec_eval_pctx_str(void *ctx, ngx_rtmp_eval_t *e, ngx_str_t *ret) +{ + *ret = *(ngx_str_t *) ((u_char *) ctx + e->offset); +} + + +static ngx_rtmp_eval_t ngx_rtmp_exec_push_specific_eval[] = { + + { ngx_string("name"), + ngx_rtmp_exec_eval_ctx_cstr, + offsetof(ngx_rtmp_exec_ctx_t, name) }, + + { ngx_string("args"), + ngx_rtmp_exec_eval_ctx_cstr, + offsetof(ngx_rtmp_exec_ctx_t, args) }, + + ngx_rtmp_null_eval +}; + + +static ngx_rtmp_eval_t * ngx_rtmp_exec_push_eval[] = { + ngx_rtmp_eval_session, + ngx_rtmp_exec_push_specific_eval, + NULL +}; + + +static ngx_rtmp_eval_t ngx_rtmp_exec_pull_specific_eval[] = { + + { ngx_string("name"), + ngx_rtmp_exec_eval_pctx_str, + offsetof(ngx_rtmp_exec_pull_ctx_t, name) }, + + { ngx_string("app"), + ngx_rtmp_exec_eval_pctx_str, + offsetof(ngx_rtmp_exec_pull_ctx_t, app) }, + + ngx_rtmp_null_eval +}; + + +static ngx_rtmp_eval_t * ngx_rtmp_exec_pull_eval[] = { + ngx_rtmp_exec_pull_specific_eval, + NULL +}; + + +static ngx_rtmp_eval_t ngx_rtmp_exec_event_specific_eval[] = { + + { ngx_string("name"), + ngx_rtmp_exec_eval_ctx_cstr, + offsetof(ngx_rtmp_exec_ctx_t, name) }, + + { ngx_string("args"), + ngx_rtmp_exec_eval_ctx_cstr, + offsetof(ngx_rtmp_exec_ctx_t, args) }, + + { ngx_string("path"), + ngx_rtmp_exec_eval_ctx_str, + offsetof(ngx_rtmp_exec_ctx_t, path) }, + + { ngx_string("filename"), + ngx_rtmp_exec_eval_ctx_str, + offsetof(ngx_rtmp_exec_ctx_t, filename) }, + + { ngx_string("basename"), + ngx_rtmp_exec_eval_ctx_str, + offsetof(ngx_rtmp_exec_ctx_t, basename) }, + + { ngx_string("dirname"), + ngx_rtmp_exec_eval_ctx_str, + offsetof(ngx_rtmp_exec_ctx_t, dirname) }, + + { ngx_string("recorder"), + ngx_rtmp_exec_eval_ctx_str, + offsetof(ngx_rtmp_exec_ctx_t, recorder) }, + + ngx_rtmp_null_eval +}; + + +static ngx_rtmp_eval_t * ngx_rtmp_exec_event_eval[] = { + ngx_rtmp_eval_session, + ngx_rtmp_exec_event_specific_eval, + NULL +}; + + +static void * +ngx_rtmp_exec_create_main_conf(ngx_conf_t *cf) +{ + ngx_rtmp_exec_main_conf_t *emcf; + + emcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_exec_main_conf_t)); + if (emcf == NULL) { + return NULL; + } + + emcf->respawn_timeout = NGX_CONF_UNSET_MSEC; + emcf->kill_signal = NGX_CONF_UNSET; + + if (ngx_array_init(&emcf->static_conf, cf->pool, 1, + sizeof(ngx_rtmp_exec_conf_t)) != NGX_OK) + { + return NULL; + } + + return emcf; +} + + +static char * +ngx_rtmp_exec_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_rtmp_exec_main_conf_t *emcf = conf; + ngx_rtmp_exec_conf_t *ec; + ngx_rtmp_exec_t *e; + ngx_uint_t n; + + if (emcf->respawn_timeout == NGX_CONF_UNSET_MSEC) { + emcf->respawn_timeout = 5000; + } + +#if !(NGX_WIN32) + if (emcf->kill_signal == NGX_CONF_UNSET) { + emcf->kill_signal = SIGKILL; + } +#endif + + if (ngx_array_init(&emcf->static_exec, cf->pool, + emcf->static_conf.nelts, + sizeof(ngx_rtmp_exec_t)) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + e = ngx_array_push_n(&emcf->static_exec, emcf->static_conf.nelts); + if (e == NULL) { + return NGX_CONF_ERROR; + } + + emcf->log = &cf->cycle->new_log; + + ec = emcf->static_conf.elts; + + for (n = 0; n < emcf->static_conf.nelts; n++, e++, ec++) { + ngx_memzero(e, sizeof(*e)); + e->conf = ec; + e->managed = 1; + e->log = emcf->log; + e->respawn_timeout = emcf->respawn_timeout; + e->kill_signal = emcf->kill_signal; + } + + return NGX_CONF_OK; +} + + +static void * +ngx_rtmp_exec_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_exec_app_conf_t *eacf; + + eacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_exec_app_conf_t)); + if (eacf == NULL) { + return NULL; + } + + eacf->respawn = NGX_CONF_UNSET; + eacf->options = NGX_CONF_UNSET; + eacf->nbuckets = NGX_CONF_UNSET_UINT; + + return eacf; +} + + +static ngx_int_t +ngx_rtmp_exec_merge_confs(ngx_array_t *conf, ngx_array_t *prev) +{ + size_t n; + ngx_rtmp_exec_conf_t *ec, *pec; + + if (prev->nelts == 0) { + return NGX_OK; + } + + if (conf->nelts == 0) { + *conf = *prev; + return NGX_OK; + } + + ec = ngx_array_push_n(conf, prev->nelts); + if (ec == NULL) { + return NGX_ERROR; + } + + pec = prev->elts; + for (n = 0; n < prev->nelts; n++, ec++, pec++) { + *ec = *pec; + } + + return NGX_OK; +} + + +static char * +ngx_rtmp_exec_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_exec_app_conf_t *prev = parent; + ngx_rtmp_exec_app_conf_t *conf = child; + + ngx_uint_t n; + + ngx_conf_merge_value(conf->respawn, prev->respawn, 1); + ngx_conf_merge_uint_value(conf->nbuckets, prev->nbuckets, 1024); + + for (n = 0; n < NGX_RTMP_EXEC_MAX; n++) { + if (ngx_rtmp_exec_merge_confs(&conf->conf[n], &prev->conf[n]) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (conf->conf[n].nelts) { + conf->active = 1; + prev->active = 1; + } + } + + if (conf->conf[NGX_RTMP_EXEC_PULL].nelts > 0) { + conf->pull = ngx_pcalloc(cf->pool, sizeof(void *) * conf->nbuckets); + if (conf->pull == NULL) { + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_exec_init_process(ngx_cycle_t *cycle) +{ +#if !(NGX_WIN32) + ngx_rtmp_core_main_conf_t *cmcf = ngx_rtmp_core_main_conf; + ngx_rtmp_core_srv_conf_t **cscf; + ngx_rtmp_conf_ctx_t *cctx; + ngx_rtmp_exec_main_conf_t *emcf; + ngx_rtmp_exec_t *e; + ngx_uint_t n; + + if (cmcf == NULL || cmcf->servers.nelts == 0) { + return NGX_OK; + } + + /* execs are always started by the first worker */ + if (ngx_process_slot) { + return NGX_OK; + } + + cscf = cmcf->servers.elts; + cctx = (*cscf)->ctx; + emcf = cctx->main_conf[ngx_rtmp_exec_module.ctx_index]; + + /* FreeBSD note: + * When worker is restarted, child process (ffmpeg) will + * not be terminated if it's connected to another + * (still alive) worker. That leads to starting + * another instance of exec_static process. + * Need to kill previously started processes. + * + * On Linux "prctl" syscall is used to kill child + * when nginx worker is terminated. + */ + + e = emcf->static_exec.elts; + for (n = 0; n < emcf->static_exec.nelts; ++n, ++e) { + e->respawn_evt.data = e; + e->respawn_evt.log = e->log; + e->respawn_evt.handler = ngx_rtmp_exec_respawn; + ngx_post_event((&e->respawn_evt), &ngx_rtmp_init_queue); + } +#endif + + return NGX_OK; +} + + +#if !(NGX_WIN32) +static void +ngx_rtmp_exec_respawn(ngx_event_t *ev) +{ + ngx_rtmp_exec_run((ngx_rtmp_exec_t *) ev->data); +} + + +static void +ngx_rtmp_exec_child_dead(ngx_event_t *ev) +{ + ngx_connection_t *dummy_conn = ev->data; + ngx_rtmp_exec_t *e; + + e = dummy_conn->data; + + ngx_log_error(NGX_LOG_INFO, e->log, 0, + "exec: child %ui exited; %s", (ngx_int_t) e->pid, + e->respawn_timeout == NGX_CONF_UNSET_MSEC ? "respawning" : + "ignoring"); + + ngx_rtmp_exec_kill(e, 0); + + if (e->respawn_timeout == NGX_CONF_UNSET_MSEC) { + return; + } + + if (e->respawn_timeout == 0) { + ngx_rtmp_exec_run(e); + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, + "exec: shedule respawn %Mmsec", e->respawn_timeout); + + e->respawn_evt.data = e; + e->respawn_evt.log = e->log; + e->respawn_evt.handler = ngx_rtmp_exec_respawn; + + ngx_add_timer(&e->respawn_evt, e->respawn_timeout); +} + + +static ngx_int_t +ngx_rtmp_exec_kill(ngx_rtmp_exec_t *e, ngx_int_t kill_signal) +{ + if (e->respawn_evt.timer_set) { + ngx_del_timer(&e->respawn_evt); + } + + if (e->read_evt.active) { + ngx_del_event(&e->read_evt, NGX_READ_EVENT, 0); + } + + if (e->active == 0) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, e->log, 0, + "exec: terminating child %ui", (ngx_int_t) e->pid); + + e->active = 0; + close(e->pipefd); + if (e->save_pid) { + *e->save_pid = NGX_INVALID_PID; + } + + if (kill_signal == 0) { + return NGX_OK; + } + + if (kill(e->pid, kill_signal) == -1) { + ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, + "exec: kill failed pid=%i", (ngx_int_t) e->pid); + } else { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, + "exec: killed pid=%i", (ngx_int_t) e->pid); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_exec_run(ngx_rtmp_exec_t *e) +{ + int fd, ret, maxfd, pipefd[2]; + char **args, **arg_out; + ngx_pid_t pid; + ngx_str_t *arg_in, a; + ngx_uint_t n; + ngx_rtmp_exec_conf_t *ec; + + ec = e->conf; + + ngx_log_error(NGX_LOG_INFO, e->log, 0, + "exec: starting %s child '%V'", + e->managed ? "managed" : "unmanaged", &ec->cmd); + + pipefd[0] = -1; + pipefd[1] = -1; + + if (e->managed) { + + if (e->active) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, e->log, 0, + "exec: already active '%V'", &ec->cmd); + return NGX_OK; + } + + if (pipe(pipefd) == -1) { + ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, + "exec: pipe failed"); + return NGX_ERROR; + } + + /* make pipe write end survive through exec */ + + ret = fcntl(pipefd[1], F_GETFD); + + if (ret != -1) { + ret &= ~FD_CLOEXEC; + ret = fcntl(pipefd[1], F_SETFD, ret); + } + + if (ret == -1) { + + close(pipefd[0]); + close(pipefd[1]); + + ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, + "exec: fcntl failed"); + + return NGX_ERROR; + } + } + + pid = fork(); + + switch (pid) { + + case -1: + + /* failure */ + + if (pipefd[0] != -1) { + close(pipefd[0]); + } + + if (pipefd[1] != -1) { + close(pipefd[1]); + } + + ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, + "exec: fork failed"); + + return NGX_ERROR; + + case 0: + + /* child */ + +#if (NGX_LINUX) + if (e->managed) { + prctl(PR_SET_PDEATHSIG, e->kill_signal, 0, 0, 0); + } +#endif + + /* close all descriptors but pipe write end */ + + maxfd = sysconf(_SC_OPEN_MAX); + for (fd = 0; fd < maxfd; ++fd) { + if (fd == pipefd[1]) { + continue; + } + + close(fd); + } + + fd = open("/dev/null", O_RDWR); + + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + + args = ngx_alloc((ec->args.nelts + 2) * sizeof(char *), e->log); + if (args == NULL) { + exit(1); + } + + arg_in = ec->args.elts; + arg_out = args; + *arg_out++ = (char *) ec->cmd.data; + + for (n = 0; n < ec->args.nelts; n++, ++arg_in) { + + if (e->eval == NULL) { + a = *arg_in; + } else { + ngx_rtmp_eval(e->eval_ctx, arg_in, e->eval, &a, e->log); + } + + if (ngx_rtmp_eval_streams(&a) != NGX_DONE) { + continue; + } + + *arg_out++ = (char *) a.data; + } + + *arg_out = NULL; + +#if (NGX_DEBUG) + { + char **p; + + for (p = args; *p; p++) { + ngx_write_fd(STDERR_FILENO, "'", 1); + ngx_write_fd(STDERR_FILENO, *p, strlen(*p)); + ngx_write_fd(STDERR_FILENO, "' ", 2); + } + + ngx_write_fd(STDERR_FILENO, "\n", 1); + } +#endif + + if (execvp((char *) ec->cmd.data, args) == -1) { + char *msg; + + msg = strerror(errno); + + ngx_write_fd(STDERR_FILENO, "execvp error: ", 14); + ngx_write_fd(STDERR_FILENO, msg, strlen(msg)); + ngx_write_fd(STDERR_FILENO, "\n", 1); + + exit(1); + } + + break; + + default: + + /* parent */ + + if (pipefd[1] != -1) { + close(pipefd[1]); + } + + if (pipefd[0] != -1) { + + e->active = 1; + e->pid = pid; + e->pipefd = pipefd[0]; + + if (e->save_pid) { + *e->save_pid = pid; + } + + e->dummy_conn.fd = e->pipefd; + e->dummy_conn.data = e; + e->dummy_conn.read = &e->read_evt; + e->dummy_conn.write = &e->write_evt; + e->read_evt.data = &e->dummy_conn; + e->write_evt.data = &e->dummy_conn; + + e->read_evt.log = e->log; + e->read_evt.handler = ngx_rtmp_exec_child_dead; + + if (ngx_add_event(&e->read_evt, NGX_READ_EVENT, 0) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, e->log, ngx_errno, + "exec: failed to add child control event"); + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, e->log, 0, + "exec: child '%V' started pid=%i", + &ec->cmd, (ngx_int_t) pid); + break; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_exec_init_ctx(ngx_rtmp_session_t *s, u_char name[NGX_RTMP_MAX_NAME], + u_char args[NGX_RTMP_MAX_ARGS], ngx_uint_t flags) +{ + ngx_uint_t n; + ngx_array_t *push_conf; + ngx_rtmp_exec_t *e; + ngx_rtmp_exec_ctx_t *ctx; + ngx_rtmp_exec_conf_t *ec; + ngx_rtmp_exec_app_conf_t *eacf; + ngx_rtmp_exec_main_conf_t *emcf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + + if (ctx != NULL) { + goto done; + } + + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_exec_ctx_t)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_exec_module); + + eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module); + + emcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_exec_module); + + push_conf = &eacf->conf[NGX_RTMP_EXEC_PUSH]; + + if (push_conf->nelts > 0) { + + if (ngx_array_init(&ctx->push_exec, s->connection->pool, + push_conf->nelts, + sizeof(ngx_rtmp_exec_t)) != NGX_OK) + { + return NGX_ERROR; + } + + e = ngx_array_push_n(&ctx->push_exec, push_conf->nelts); + + if (e == NULL) { + return NGX_ERROR; + } + + ec = push_conf->elts; + + for (n = 0; n < push_conf->nelts; n++, e++, ec++) { + ngx_memzero(e, sizeof(*e)); + e->conf = ec; + e->managed = 1; + e->log = s->connection->log; + e->eval = ngx_rtmp_exec_push_eval; + e->eval_ctx = s; + e->kill_signal = emcf->kill_signal; + e->respawn_timeout = (eacf->respawn ? emcf->respawn_timeout : + NGX_CONF_UNSET_MSEC); + } + } + +done: + + ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME); + ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS); + + ctx->flags |= flags; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_exec_init_pull_ctx(ngx_rtmp_session_t *s, + u_char name[NGX_RTMP_MAX_NAME]) +{ + size_t len; + ngx_uint_t n; + ngx_pool_t *pool; + ngx_array_t *pull_conf; + ngx_rtmp_exec_t *e; + ngx_rtmp_exec_ctx_t *ctx; + ngx_rtmp_exec_conf_t *ec; + ngx_rtmp_exec_pull_ctx_t *pctx, **ppctx; + ngx_rtmp_exec_app_conf_t *eacf; + ngx_rtmp_exec_main_conf_t *emcf; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + if (ctx->pull != NULL) { + return NGX_OK; + } + + eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module); + + pull_conf = &eacf->conf[NGX_RTMP_EXEC_PULL]; + + if (pull_conf->nelts == 0) { + return NGX_OK; + } + + emcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_exec_module); + + len = ngx_strlen(name); + + ppctx = &eacf->pull[ngx_hash_key(name, len) % eacf->nbuckets]; + + for (; *ppctx; ppctx = &(*ppctx)->next) { + pctx = *ppctx; + + if (pctx->name.len == len && + ngx_strncmp(name, pctx->name.data, len) == 0) + { + goto done; + } + } + + pool = ngx_create_pool(4096, emcf->log); + if (pool == NULL) { + return NGX_ERROR; + } + + pctx = ngx_pcalloc(pool, sizeof(ngx_rtmp_exec_pull_ctx_t)); + if (pctx == NULL) { + goto error; + } + + pctx->pool = pool; + pctx->name.len = len; + pctx->name.data = ngx_palloc(pool, len); + + if (pctx->name.data == NULL) { + goto error; + } + + ngx_memcpy(pctx->name.data, name, len); + + pctx->app.len = s->app.len; + pctx->app.data = ngx_palloc(pool, s->app.len); + + if (pctx->app.data == NULL) { + goto error; + } + + ngx_memcpy(pctx->app.data, s->app.data, s->app.len); + + if (ngx_array_init(&pctx->pull_exec, pool, pull_conf->nelts, + sizeof(ngx_rtmp_exec_t)) != NGX_OK) + { + goto error; + } + + e = ngx_array_push_n(&pctx->pull_exec, pull_conf->nelts); + if (e == NULL) { + goto error; + } + + ec = pull_conf->elts; + for (n = 0; n < pull_conf->nelts; n++, e++, ec++) { + ngx_memzero(e, sizeof(*e)); + e->conf = ec; + e->managed = 1; + e->log = emcf->log; + e->eval = ngx_rtmp_exec_pull_eval; + e->eval_ctx = pctx; + e->kill_signal = emcf->kill_signal; + e->respawn_timeout = (eacf->respawn ? emcf->respawn_timeout : + NGX_CONF_UNSET_MSEC); + } + + *ppctx = pctx; + +done: + + ctx->pull = pctx; + ctx->pull->counter++; + + return NGX_OK; + +error: + + ngx_destroy_pool(pool); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_exec_filter(ngx_rtmp_session_t *s, ngx_rtmp_exec_conf_t *ec) +{ + size_t len; + ngx_str_t *v; + ngx_uint_t n; + ngx_rtmp_exec_ctx_t *ctx; + + if (ec->names.nelts == 0) { + return NGX_OK; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + + len = ngx_strlen(ctx->name); + + v = ec->names.elts; + for (n = 0; n < ec->names.nelts; n++, s++) { + if (v->len == len && ngx_strncmp(v->data, ctx->name, len) == 0) { + return NGX_OK; + } + } + + return NGX_DECLINED; +} + + +static void +ngx_rtmp_exec_unmanaged(ngx_rtmp_session_t *s, ngx_array_t *e, const char *op) +{ + ngx_uint_t n; + ngx_rtmp_exec_t en; + ngx_rtmp_exec_conf_t *ec; + + if (e->nelts == 0) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "exec: %s %uz unmanaged command(s)", op, e->nelts); + + ec = e->elts; + for (n = 0; n < e->nelts; n++, ec++) { + if (ngx_rtmp_exec_filter(s, ec) != NGX_OK) { + continue; + } + + ngx_memzero(&en, sizeof(ngx_rtmp_exec_t)); + + en.conf = ec; + en.eval = ngx_rtmp_exec_event_eval; + en.eval_ctx = s; + en.log = s->connection->log; + + ngx_rtmp_exec_run(&en); + } +} + + +static void +ngx_rtmp_exec_managed(ngx_rtmp_session_t *s, ngx_array_t *e, const char *op) +{ + ngx_uint_t n; + ngx_rtmp_exec_t *en; + + if (e->nelts == 0) { + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "exec: %s %uz managed command(s)", op, e->nelts); + + en = e->elts; + for (n = 0; n < e->nelts; n++, en++) { + if (ngx_rtmp_exec_filter(s, en->conf) == NGX_OK) { + ngx_rtmp_exec_run(en); + } + } +} + + +static ngx_int_t +ngx_rtmp_exec_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_exec_ctx_t *ctx; + ngx_rtmp_exec_app_conf_t *eacf; + + eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module); + + if (eacf == NULL || !eacf->active) { + goto next; + } + + if (s->auto_pushed) { + goto next; + } + + if (ngx_rtmp_exec_init_ctx(s, v->name, v->args, NGX_RTMP_EXEC_PUBLISHING) + != NGX_OK) + { + goto next; + } + + ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_PUBLISH], "publish"); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + + ngx_rtmp_exec_managed(s, &ctx->push_exec, "push"); + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_exec_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_exec_ctx_t *ctx; + ngx_rtmp_exec_pull_ctx_t *pctx; + ngx_rtmp_exec_app_conf_t *eacf; + + eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module); + + if (eacf == NULL || !eacf->active) { + goto next; + } + + if (ngx_rtmp_exec_init_ctx(s, v->name, v->args, NGX_RTMP_EXEC_PLAYING) + != NGX_OK) + { + goto next; + } + + ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_PLAY], "play"); + + if (ngx_rtmp_exec_init_pull_ctx(s, v->name) != NGX_OK) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + pctx = ctx->pull; + + if (pctx && pctx->counter == 1) { + ngx_rtmp_exec_managed(s, &pctx->pull_exec, "pull"); + } + +next: + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_exec_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + size_t n; + ngx_rtmp_exec_t *e; + ngx_rtmp_exec_ctx_t *ctx; + ngx_rtmp_exec_pull_ctx_t *pctx, **ppctx; + ngx_rtmp_exec_app_conf_t *eacf; + + eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module); + if (eacf == NULL) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + if (ctx == NULL) { + goto next; + } + + if (ctx->flags & NGX_RTMP_EXEC_PUBLISHING) { + ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_PUBLISH_DONE], + "publish_done"); + } + + if (ctx->flags & NGX_RTMP_EXEC_PLAYING) { + ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_PLAY_DONE], + "play_done"); + } + + ctx->flags = 0; + + if (ctx->push_exec.nelts > 0) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "exec: delete %uz push command(s)", + ctx->push_exec.nelts); + + e = ctx->push_exec.elts; + for (n = 0; n < ctx->push_exec.nelts; n++, e++) { + ngx_rtmp_exec_kill(e, e->kill_signal); + } + } + + pctx = ctx->pull; + + if (pctx && --pctx->counter == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "exec: delete %uz pull command(s)", + pctx->pull_exec.nelts); + + e = pctx->pull_exec.elts; + for (n = 0; n < pctx->pull_exec.nelts; n++, e++) { + ngx_rtmp_exec_kill(e, e->kill_signal); + } + + ppctx = &eacf->pull[ngx_hash_key(pctx->name.data, pctx->name.len) % + eacf->nbuckets]; + + for (; *ppctx; ppctx = &(*ppctx)->next) { + if (pctx == *ppctx) { + *ppctx = pctx->next; + break; + } + } + + ngx_destroy_pool(pctx->pool); + } + + ctx->pull = NULL; + +next: + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_exec_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v) +{ + u_char c; + ngx_uint_t ext, dir; + ngx_rtmp_exec_ctx_t *ctx; + ngx_rtmp_exec_app_conf_t *eacf; + + if (s->auto_pushed) { + goto next; + } + + eacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_exec_module); + if (eacf == NULL || !eacf->active) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_exec_module); + if (ctx == NULL) { + goto next; + } + + ctx->recorder = v->recorder; + ctx->path = v->path; + + ctx->dirname.data = ctx->path.data; + ctx->dirname.len = 0; + + for (dir = ctx->path.len; dir > 0; dir--) { + c = ctx->path.data[dir - 1]; + if (c == '/' || c == '\\') { + ctx->dirname.len = dir - 1; + break; + } + } + + ctx->filename.data = ctx->path.data + dir; + ctx->filename.len = ctx->path.len - dir; + + ctx->basename = ctx->filename; + + for (ext = ctx->filename.len; ext > 0; ext--) { + if (ctx->filename.data[ext - 1] == '.') { + ctx->basename.len = ext - 1; + break; + } + } + + ngx_rtmp_exec_unmanaged(s, &eacf->conf[NGX_RTMP_EXEC_RECORD_DONE], + "record_done"); + + ngx_str_null(&v->recorder); + ngx_str_null(&v->path); + +next: + return next_record_done(s, v); +} +#endif /* NGX_WIN32 */ + + +static char * +ngx_rtmp_exec_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + size_t n, nargs; + ngx_str_t *s, *value, v; + ngx_array_t *confs; + ngx_rtmp_exec_conf_t *ec; + ngx_rtmp_exec_app_conf_t *eacf; + + confs = (ngx_array_t *) (p + cmd->offset); + + eacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_exec_module); + + if (confs->nalloc == 0 && ngx_array_init(confs, cf->pool, 1, + sizeof(ngx_rtmp_exec_conf_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ec = ngx_array_push(confs); + if (ec == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(ec, sizeof(ngx_rtmp_exec_conf_t)); + + /* type is undefined for explicit execs */ + + ec->type = NGX_CONF_UNSET_UINT; + ec->cmd = value[1]; + + if (ngx_array_init(&ec->names, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + nargs = cf->args->nelts - 2; + if (ngx_array_init(&ec->args, cf->pool, nargs, sizeof(ngx_str_t)) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + for (n = 2; n < cf->args->nelts; n++) { + + v = value[n]; + + if (eacf->options == 1) { + + if (v.len >= 5 && ngx_strncmp(v.data, "name=", 5) == 0) { + + s = ngx_array_push(&ec->names); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + v.data += 5; + v.len -= 5; + + *s = v; + + continue; + } + } + + s = ngx_array_push(&ec->args); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + *s = v; + } + + return NGX_CONF_OK; +} + +/* +static char * +ngx_rtmp_exec_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_str_t *value; + ngx_conf_t save; + ngx_array_t *confs; + ngx_rtmp_conf_ctx_t *ctx, *pctx; + ngx_rtmp_exec_conf_t *ec, *eec; + ngx_rtmp_exec_app_conf_t *eacf; + ngx_rtmp_exec_main_conf_t *emcf; + + value = cf->args->elts; + + eacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_exec_module); + + emcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_exec_module); + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + pctx = cf->ctx; + + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + + ec = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_exec_conf_t)); + if (ec == NULL) { + return NGX_CONF_ERROR; + } + + ec->id = value[1]; + ec->type = NGX_CONF_UNSET_UINT; + + ctx->app_conf[ngx_rtmp_exec_module.ctx_index] = ec; + + save = *cf; + + cf->ctx = ctx; + cf->cmd_type = NGX_RTMP_EXEC_CONF; + + rv = ngx_conf_parse(cf, NULL); + *cf= save; + + switch (ec->type) { + + case NGX_RTMP_EXEC_STATIC: + confs = &emcf->static_conf; + break; + + case NGX_CONF_UNSET_UINT: + return "unspecified exec type"; + + default: + confs = &eacf->conf[ec->type]; + } + + if (confs->nalloc == 0 && ngx_array_init(confs, cf->pool, 1, + sizeof(ngx_rtmp_exec_conf_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + eec = ngx_array_push(confs); + if (eec == NULL) { + return NGX_CONF_ERROR; + } + + *eec = *ec; + + return rv; +} +*/ + +static char * +ngx_rtmp_exec_kill_signal(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_exec_main_conf_t *emcf = conf; + + ngx_str_t *value; + + value = cf->args->elts; + value++; + + emcf->kill_signal = ngx_atoi(value->data, value->len); + if (emcf->kill_signal != NGX_ERROR) { + return NGX_CONF_OK; + } + +#define NGX_RMTP_EXEC_SIGNAL(name) \ + if (value->len == sizeof(#name) - 1 && \ + ngx_strncasecmp(value->data, (u_char *) #name, value->len) == 0) \ + { \ + emcf->kill_signal = SIG##name; \ + return NGX_CONF_OK; \ + } + + /* POSIX.1-1990 signals */ + +#if !(NGX_WIN32) + NGX_RMTP_EXEC_SIGNAL(HUP); + NGX_RMTP_EXEC_SIGNAL(INT); + NGX_RMTP_EXEC_SIGNAL(QUIT); + NGX_RMTP_EXEC_SIGNAL(ILL); + NGX_RMTP_EXEC_SIGNAL(ABRT); + NGX_RMTP_EXEC_SIGNAL(FPE); + NGX_RMTP_EXEC_SIGNAL(KILL); + NGX_RMTP_EXEC_SIGNAL(SEGV); + NGX_RMTP_EXEC_SIGNAL(PIPE); + NGX_RMTP_EXEC_SIGNAL(ALRM); + NGX_RMTP_EXEC_SIGNAL(TERM); + NGX_RMTP_EXEC_SIGNAL(USR1); + NGX_RMTP_EXEC_SIGNAL(USR2); + NGX_RMTP_EXEC_SIGNAL(CHLD); + NGX_RMTP_EXEC_SIGNAL(CONT); + NGX_RMTP_EXEC_SIGNAL(STOP); + NGX_RMTP_EXEC_SIGNAL(TSTP); + NGX_RMTP_EXEC_SIGNAL(TTIN); + NGX_RMTP_EXEC_SIGNAL(TTOU); +#endif + +#undef NGX_RMTP_EXEC_SIGNAL + + return "unknown signal"; +} + + +static ngx_int_t +ngx_rtmp_exec_postconfiguration(ngx_conf_t *cf) +{ +#if !(NGX_WIN32) + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_exec_publish; + + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_exec_play; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_exec_close_stream; + + next_record_done = ngx_rtmp_record_done; + ngx_rtmp_record_done = ngx_rtmp_exec_record_done; + +#endif /* NGX_WIN32 */ + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c new file mode 100644 index 0000000..4776e54 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c @@ -0,0 +1,675 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_play_module.h" +#include "ngx_rtmp_codec_module.h" +#include "ngx_rtmp_streams.h" + + +static ngx_int_t ngx_rtmp_flv_postconfiguration(ngx_conf_t *cf); +static void ngx_rtmp_flv_read_meta(ngx_rtmp_session_t *s, ngx_file_t *f); +static ngx_int_t ngx_rtmp_flv_timestamp_to_offset(ngx_rtmp_session_t *s, + ngx_file_t *f, ngx_int_t timestamp); +static ngx_int_t ngx_rtmp_flv_init(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_int_t aindex, ngx_int_t vindex); +static ngx_int_t ngx_rtmp_flv_start(ngx_rtmp_session_t *s, ngx_file_t *f); +static ngx_int_t ngx_rtmp_flv_seek(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_uint_t offset); +static ngx_int_t ngx_rtmp_flv_stop(ngx_rtmp_session_t *s, ngx_file_t *f); +static ngx_int_t ngx_rtmp_flv_send(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_uint_t *ts); + + +typedef struct { + ngx_uint_t nelts; + ngx_uint_t offset; +} ngx_rtmp_flv_index_t; + + +typedef struct { + ngx_int_t offset; + ngx_int_t start_timestamp; + ngx_event_t write_evt; + uint32_t last_audio; + uint32_t last_video; + ngx_uint_t msg_mask; + uint32_t epoch; + + unsigned meta_read:1; + ngx_rtmp_flv_index_t filepositions; + ngx_rtmp_flv_index_t times; +} ngx_rtmp_flv_ctx_t; + + +#define NGX_RTMP_FLV_BUFFER (1024*1024) +#define NGX_RTMP_FLV_BUFLEN_ADDON 1000 +#define NGX_RTMP_FLV_TAG_HEADER 11 +#define NGX_RTMP_FLV_DATA_OFFSET 13 + + +static u_char ngx_rtmp_flv_buffer[ + NGX_RTMP_FLV_BUFFER]; +static u_char ngx_rtmp_flv_header[ + NGX_RTMP_FLV_TAG_HEADER]; + + +static ngx_rtmp_module_t ngx_rtmp_flv_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_flv_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_flv_module = { + NGX_MODULE_V1, + &ngx_rtmp_flv_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_RTMP_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_rtmp_flv_fill_index(ngx_rtmp_amf_ctx_t *ctx, ngx_rtmp_flv_index_t *idx) +{ + uint32_t nelts; + ngx_buf_t *b; + + /* we have AMF array pointed by context; + * need to extract its size (4 bytes) & + * save offset of actual array data */ + + b = ctx->link->buf; + + if (b->last - b->pos < (ngx_int_t) ctx->offset + 4) { + return NGX_ERROR; + } + + ngx_rtmp_rmemcpy(&nelts, b->pos + ctx->offset, 4); + + idx->nelts = nelts; + idx->offset = ctx->offset + 4; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_flv_init_index(ngx_rtmp_session_t *s, ngx_chain_t *in) +{ + ngx_rtmp_flv_ctx_t *ctx; + + static ngx_rtmp_amf_ctx_t filepositions_ctx; + static ngx_rtmp_amf_ctx_t times_ctx; + + static ngx_rtmp_amf_elt_t in_keyframes[] = { + + { NGX_RTMP_AMF_ARRAY | NGX_RTMP_AMF_CONTEXT, + ngx_string("filepositions"), + &filepositions_ctx, 0 }, + + { NGX_RTMP_AMF_ARRAY | NGX_RTMP_AMF_CONTEXT, + ngx_string("times"), + ×_ctx, 0 } + }; + + static ngx_rtmp_amf_elt_t in_inf[] = { + + { NGX_RTMP_AMF_OBJECT, + ngx_string("keyframes"), + in_keyframes, sizeof(in_keyframes) } + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL || in == NULL) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: init index"); + + ngx_memzero(&filepositions_ctx, sizeof(filepositions_ctx)); + ngx_memzero(×_ctx, sizeof(times_ctx)); + + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: init index error"); + return NGX_OK; + } + + if (filepositions_ctx.link && ngx_rtmp_flv_fill_index(&filepositions_ctx, + &ctx->filepositions) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: failed to init filepositions"); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: filepositions nelts=%ui offset=%ui", + ctx->filepositions.nelts, ctx->filepositions.offset); + + if (times_ctx.link && ngx_rtmp_flv_fill_index(×_ctx, + &ctx->times) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: failed to init times"); + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: times nelts=%ui offset=%ui", + ctx->times.nelts, ctx->times.offset); + + return NGX_OK; +} + + +static double +ngx_rtmp_flv_index_value(void *src) +{ + double v; + + ngx_rtmp_rmemcpy(&v, src, 8); + + return v; +} + + +static ngx_int_t +ngx_rtmp_flv_timestamp_to_offset(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_int_t timestamp) +{ + ngx_rtmp_flv_ctx_t *ctx; + ssize_t n, size; + ngx_uint_t offset, index, ret, nelts; + double v; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + goto rewind; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: lookup index start timestamp=%i", + timestamp); + + if (ctx->meta_read == 0) { + ngx_rtmp_flv_read_meta(s, f); + ctx->meta_read = 1; + } + + if (timestamp <= 0 || ctx->filepositions.nelts == 0 + || ctx->times.nelts == 0) + { + goto rewind; + } + + /* read index table from file given offset */ + offset = NGX_RTMP_FLV_DATA_OFFSET + NGX_RTMP_FLV_TAG_HEADER + + ctx->times.offset; + + /* index should fit in the buffer */ + nelts = ngx_min(ctx->times.nelts, sizeof(ngx_rtmp_flv_buffer) / 9); + size = nelts * 9; + + n = ngx_read_file(f, ngx_rtmp_flv_buffer, size, offset); + + if (n != size) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: could not read times index"); + goto rewind; + } + + /*TODO: implement binary search */ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: lookup times nelts=%ui", nelts); + + for (index = 0; index < nelts - 1; ++index) { + v = ngx_rtmp_flv_index_value(ngx_rtmp_flv_buffer + + index * 9 + 1) * 1000; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: lookup times index=%ui value=%ui", + index, (ngx_uint_t) v); + + if (timestamp < v) { + break; + } + } + + if (index >= ctx->filepositions.nelts) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: index out of bounds: %ui>=%ui", + index, ctx->filepositions.nelts); + goto rewind; + } + + /* take value from filepositions */ + offset = NGX_RTMP_FLV_DATA_OFFSET + NGX_RTMP_FLV_TAG_HEADER + + ctx->filepositions.offset + index * 9; + + n = ngx_read_file(f, ngx_rtmp_flv_buffer, 8, offset + 1); + + if (n != 8) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: could not read filepositions index"); + goto rewind; + } + + ret = (ngx_uint_t) ngx_rtmp_flv_index_value(ngx_rtmp_flv_buffer); + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: lookup index timestamp=%i offset=%ui", + timestamp, ret); + + return ret; + +rewind: + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: lookup index timestamp=%i offset=begin", + timestamp); + + return NGX_RTMP_FLV_DATA_OFFSET; +} + + +static void +ngx_rtmp_flv_read_meta(ngx_rtmp_session_t *s, ngx_file_t *f) +{ + ngx_rtmp_flv_ctx_t *ctx; + ssize_t n; + ngx_rtmp_header_t h; + ngx_chain_t *out, in; + ngx_buf_t in_buf; + ngx_rtmp_core_srv_conf_t *cscf; + uint32_t size; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: read meta"); + + /* read tag header */ + n = ngx_read_file(f, ngx_rtmp_flv_header, sizeof(ngx_rtmp_flv_header), + NGX_RTMP_FLV_DATA_OFFSET); + + if (n != sizeof(ngx_rtmp_flv_header)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: could not read metadata tag header"); + return; + } + + if (ngx_rtmp_flv_header[0] != NGX_RTMP_MSG_AMF_META) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: first tag is not metadata, giving up"); + return; + } + + ngx_memzero(&h, sizeof(h)); + + h.type = NGX_RTMP_MSG_AMF_META; + h.msid = NGX_RTMP_MSID; + h.csid = NGX_RTMP_CSID_AMF; + + size = 0; + ngx_rtmp_rmemcpy(&size, ngx_rtmp_flv_header + 1, 3); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: metadata size=%D", size); + + if (size > sizeof(ngx_rtmp_flv_buffer)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: too big metadata"); + return; + } + + /* read metadata */ + n = ngx_read_file(f, ngx_rtmp_flv_buffer, size, + sizeof(ngx_rtmp_flv_header) + + NGX_RTMP_FLV_DATA_OFFSET); + + if (n != (ssize_t) size) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: could not read metadata"); + return; + } + + /* prepare input chain */ + ngx_memzero(&in, sizeof(in)); + ngx_memzero(&in_buf, sizeof(in_buf)); + + in.buf = &in_buf; + in_buf.pos = ngx_rtmp_flv_buffer; + in_buf.last = ngx_rtmp_flv_buffer + size; + + ngx_rtmp_flv_init_index(s, &in); + + /* output chain */ + out = ngx_rtmp_append_shared_bufs(cscf, NULL, &in); + + ngx_rtmp_prepare_message(s, &h, NULL, out); + ngx_rtmp_send_message(s, out, 0); + ngx_rtmp_free_shared_chain(cscf, out); +} + + +static ngx_int_t +ngx_rtmp_flv_send(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_uint_t *ts) +{ + ngx_rtmp_flv_ctx_t *ctx; + uint32_t last_timestamp; + ngx_rtmp_header_t h, lh; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_chain_t *out, in; + ngx_buf_t in_buf; + ngx_int_t rc; + ssize_t n; + uint32_t buflen, end_timestamp, size; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ctx->offset == -1) { + ctx->offset = ngx_rtmp_flv_timestamp_to_offset(s, f, + ctx->start_timestamp); + ctx->start_timestamp = -1; /* set later from actual timestamp */ + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: read tag at offset=%i", ctx->offset); + + /* read tag header */ + n = ngx_read_file(f, ngx_rtmp_flv_header, + sizeof(ngx_rtmp_flv_header), ctx->offset); + + if (n != sizeof(ngx_rtmp_flv_header)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: could not read flv tag header"); + return NGX_DONE; + } + + /* parse header fields */ + ngx_memzero(&h, sizeof(h)); + + h.msid = NGX_RTMP_MSID; + h.type = ngx_rtmp_flv_header[0]; + + size = 0; + + ngx_rtmp_rmemcpy(&size, ngx_rtmp_flv_header + 1, 3); + ngx_rtmp_rmemcpy(&h.timestamp, ngx_rtmp_flv_header + 4, 3); + + ((u_char *) &h.timestamp)[3] = ngx_rtmp_flv_header[7]; + + ctx->offset += (sizeof(ngx_rtmp_flv_header) + size + 4); + + last_timestamp = 0; + + switch (h.type) { + + case NGX_RTMP_MSG_AUDIO: + h.csid = NGX_RTMP_CSID_AUDIO; + last_timestamp = ctx->last_audio; + ctx->last_audio = h.timestamp; + break; + + case NGX_RTMP_MSG_VIDEO: + h.csid = NGX_RTMP_CSID_VIDEO; + last_timestamp = ctx->last_video; + ctx->last_video = h.timestamp; + break; + + default: + return NGX_OK; + } + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: read tag type=%i size=%uD timestamp=%uD " + "last_timestamp=%uD", + (ngx_int_t) h.type,size, h.timestamp, last_timestamp); + + lh = h; + lh.timestamp = last_timestamp; + + if (size > sizeof(ngx_rtmp_flv_buffer)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: too big message: %D>%uz", size, + sizeof(ngx_rtmp_flv_buffer)); + goto next; + } + + /* read tag body */ + n = ngx_read_file(f, ngx_rtmp_flv_buffer, size, + ctx->offset - size - 4); + + if (n != (ssize_t) size) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "flv: could not read flv tag"); + return NGX_ERROR; + } + + /* prepare input chain */ + ngx_memzero(&in, sizeof(in)); + ngx_memzero(&in_buf, sizeof(in_buf)); + + in.buf = &in_buf; + in_buf.pos = ngx_rtmp_flv_buffer; + in_buf.last = ngx_rtmp_flv_buffer + size; + + /* output chain */ + out = ngx_rtmp_append_shared_bufs(cscf, NULL, &in); + + ngx_rtmp_prepare_message(s, &h, ctx->msg_mask & (1 << h.type) ? + &lh : NULL, out); + rc = ngx_rtmp_send_message(s, out, 0); + ngx_rtmp_free_shared_chain(cscf, out); + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (rc != NGX_OK) { + return NGX_ERROR; + } + + ctx->msg_mask |= (1 << h.type); + +next: + if (ctx->start_timestamp == -1) { + ctx->start_timestamp = h.timestamp; + ctx->epoch = ngx_current_msec; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: start_timestamp=%i", ctx->start_timestamp); + return NGX_OK; + } + + buflen = s->buflen + NGX_RTMP_FLV_BUFLEN_ADDON; + + end_timestamp = (ngx_current_msec - ctx->epoch) + + ctx->start_timestamp + buflen; + + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: %s wait=%D timestamp=%D end_timestamp=%D bufen=%i", + h.timestamp > end_timestamp ? "schedule" : "advance", + h.timestamp > end_timestamp ? h.timestamp - end_timestamp : 0, + h.timestamp, end_timestamp, (ngx_int_t) buflen); + + s->current_time = h.timestamp; + + /* too much data sent; schedule timeout */ + if (h.timestamp > end_timestamp) { + return h.timestamp - end_timestamp; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_flv_init(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_int_t aindex, + ngx_int_t vindex) +{ + ngx_rtmp_flv_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_flv_ctx_t)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_flv_module); + } + + ngx_memzero(ctx, sizeof(*ctx)); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_flv_start(ngx_rtmp_session_t *s, ngx_file_t *f) +{ + ngx_rtmp_flv_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: start"); + + ctx->offset = -1; + ctx->msg_mask = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_flv_seek(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_uint_t timestamp) +{ + ngx_rtmp_flv_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: seek timestamp=%ui", timestamp); + + ctx->start_timestamp = timestamp; + ctx->epoch = ngx_current_msec; + ctx->offset = -1; + ctx->msg_mask = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_flv_stop(ngx_rtmp_session_t *s, ngx_file_t *f) +{ + ngx_rtmp_flv_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_flv_module); + + if (ctx == NULL) { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "flv: stop"); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_flv_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_play_main_conf_t *pmcf; + ngx_rtmp_play_fmt_t **pfmt, *fmt; + + pmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_play_module); + + pfmt = ngx_array_push(&pmcf->fmts); + + if (pfmt == NULL) { + return NGX_ERROR; + } + + fmt = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_play_fmt_t)); + + if (fmt == NULL) { + return NGX_ERROR; + } + + *pfmt = fmt; + + ngx_str_set(&fmt->name, "flv-format"); + + ngx_str_null(&fmt->pfx); /* default fmt */ + ngx_str_set(&fmt->sfx, ".flv"); + + fmt->init = ngx_rtmp_flv_init; + fmt->start = ngx_rtmp_flv_start; + fmt->seek = ngx_rtmp_flv_seek; + fmt->stop = ngx_rtmp_flv_stop; + fmt->send = ngx_rtmp_flv_send; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_handler.c b/debian/modules/nginx-rtmp/ngx_rtmp_handler.c new file mode 100644 index 0000000..ac78a6f --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_handler.c @@ -0,0 +1,895 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_amf.h" + + +static void ngx_rtmp_recv(ngx_event_t *rev); +static void ngx_rtmp_send(ngx_event_t *rev); +static void ngx_rtmp_ping(ngx_event_t *rev); +static ngx_int_t ngx_rtmp_finalize_set_chunk_size(ngx_rtmp_session_t *s); + + +ngx_uint_t ngx_rtmp_naccepted; + + +ngx_rtmp_bandwidth_t ngx_rtmp_bw_out; +ngx_rtmp_bandwidth_t ngx_rtmp_bw_in; + + +#ifdef NGX_DEBUG +char* +ngx_rtmp_message_type(uint8_t type) +{ + static char* types[] = { + "?", + "chunk_size", + "abort", + "ack", + "user", + "ack_size", + "bandwidth", + "edge", + "audio", + "video", + "?", + "?", + "?", + "?", + "?", + "amf3_meta", + "amf3_shared", + "amf3_cmd", + "amf_meta", + "amf_shared", + "amf_cmd", + "?", + "aggregate" + }; + + return type < sizeof(types) / sizeof(types[0]) + ? types[type] + : "?"; +} + + +char* +ngx_rtmp_user_message_type(uint16_t evt) +{ + static char* evts[] = { + "stream_begin", + "stream_eof", + "stream dry", + "set_buflen", + "recorded", + "", + "ping_request", + "ping_response", + }; + + return evt < sizeof(evts) / sizeof(evts[0]) + ? evts[evt] + : "?"; +} +#endif + + +void +ngx_rtmp_cycle(ngx_rtmp_session_t *s) +{ + ngx_connection_t *c; + + c = s->connection; + c->read->handler = ngx_rtmp_recv; + c->write->handler = ngx_rtmp_send; + + s->ping_evt.data = c; + s->ping_evt.log = c->log; + s->ping_evt.handler = ngx_rtmp_ping; + ngx_rtmp_reset_ping(s); + + ngx_rtmp_recv(c->read); +} + + +static ngx_chain_t * +ngx_rtmp_alloc_in_buf(ngx_rtmp_session_t *s) +{ + ngx_chain_t *cl; + ngx_buf_t *b; + size_t size; + + if ((cl = ngx_alloc_chain_link(s->in_pool)) == NULL + || (cl->buf = ngx_calloc_buf(s->in_pool)) == NULL) + { + return NULL; + } + + cl->next = NULL; + b = cl->buf; + size = s->in_chunk_size + NGX_RTMP_MAX_CHUNK_HEADER; + + b->start = b->last = b->pos = ngx_palloc(s->in_pool, size); + if (b->start == NULL) { + return NULL; + } + b->end = b->start + size; + + return cl; +} + + +void +ngx_rtmp_reset_ping(ngx_rtmp_session_t *s) +{ + ngx_rtmp_core_srv_conf_t *cscf; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + if (cscf->ping == 0) { + return; + } + + s->ping_active = 0; + s->ping_reset = 0; + ngx_add_timer(&s->ping_evt, cscf->ping); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "ping: wait %Mms", cscf->ping); +} + + +static void +ngx_rtmp_ping(ngx_event_t *pev) +{ + ngx_connection_t *c; + ngx_rtmp_session_t *s; + ngx_rtmp_core_srv_conf_t *cscf; + + c = pev->data; + s = c->data; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + /* i/o event has happened; no need to ping */ + if (s->ping_reset) { + ngx_rtmp_reset_ping(s); + return; + } + + if (s->ping_active) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "ping: unresponded"); + ngx_rtmp_finalize_session(s); + return; + } + + if (cscf->busy) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "ping: not busy between pings"); + ngx_rtmp_finalize_session(s); + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "ping: schedule %Mms", cscf->ping_timeout); + + if (ngx_rtmp_send_ping_request(s, (uint32_t)ngx_current_msec) != NGX_OK) { + ngx_rtmp_finalize_session(s); + return; + } + + s->ping_active = 1; + ngx_add_timer(pev, cscf->ping_timeout); +} + + +static void +ngx_rtmp_recv(ngx_event_t *rev) +{ + ngx_int_t n; + ngx_connection_t *c; + ngx_rtmp_session_t *s; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_header_t *h; + ngx_rtmp_stream_t *st, *st0; + ngx_chain_t *in, *head; + ngx_buf_t *b; + u_char *p, *pp, *old_pos; + size_t size, fsize, old_size; + uint8_t fmt, ext; + uint32_t csid, timestamp; + + c = rev->data; + s = c->data; + b = NULL; + old_pos = NULL; + old_size = 0; + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (c->destroyed) { + return; + } + + for( ;; ) { + + st = &s->in_streams[s->in_csid]; + + /* allocate new buffer */ + if (st->in == NULL) { + st->in = ngx_rtmp_alloc_in_buf(s); + if (st->in == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "in buf alloc failed"); + ngx_rtmp_finalize_session(s); + return; + } + } + + h = &st->hdr; + in = st->in; + b = in->buf; + + if (old_size) { + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, + "reusing formerly read data: %d", old_size); + + b->pos = b->start; + b->last = ngx_movemem(b->pos, old_pos, old_size); + + if (s->in_chunk_size_changing) { + ngx_rtmp_finalize_set_chunk_size(s); + } + + } else { + + if (old_pos) { + b->pos = b->last = b->start; + } + + n = c->recv(c, b->last, b->end - b->last); + + if (n == NGX_ERROR || n == 0) { + ngx_rtmp_finalize_session(s); + return; + } + + if (n == NGX_AGAIN) { + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + return; + } + + s->ping_reset = 1; + ngx_rtmp_update_bandwidth(&ngx_rtmp_bw_in, n); + b->last += n; + s->in_bytes += n; + + if (s->in_bytes >= 0xf0000000) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, + "resetting byte counter"); + s->in_bytes = 0; + s->in_last_ack = 0; + } + + if (s->ack_size && s->in_bytes - s->in_last_ack >= s->ack_size) { + + s->in_last_ack = s->in_bytes; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, + "sending RTMP ACK(%uD)", s->in_bytes); + + if (ngx_rtmp_send_ack(s, s->in_bytes)) { + ngx_rtmp_finalize_session(s); + return; + } + } + } + + old_pos = NULL; + old_size = 0; + + /* parse headers */ + if (b->pos == b->start) { + p = b->pos; + + /* chunk basic header */ + fmt = (*p >> 6) & 0x03; + csid = *p++ & 0x3f; + + if (csid == 0) { + if (b->last - p < 1) + continue; + csid = 64; + csid += *(uint8_t*)p++; + + } else if (csid == 1) { + if (b->last - p < 2) + continue; + csid = 64; + csid += *(uint8_t*)p++; + csid += (uint32_t)256 * (*(uint8_t*)p++); + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, c->log, 0, + "RTMP bheader fmt=%d csid=%D", + (int)fmt, csid); + + if (csid >= (uint32_t)cscf->max_streams) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "RTMP in chunk stream too big: %D >= %D", + csid, cscf->max_streams); + ngx_rtmp_finalize_session(s); + return; + } + + /* link orphan */ + if (s->in_csid == 0) { + + /* unlink from stream #0 */ + st->in = st->in->next; + + /* link to new stream */ + s->in_csid = csid; + st = &s->in_streams[csid]; + if (st->in == NULL) { + in->next = in; + } else { + in->next = st->in->next; + st->in->next = in; + } + st->in = in; + h = &st->hdr; + h->csid = csid; + } + + ext = st->ext; + timestamp = st->dtime; + if (fmt <= 2 ) { + if (b->last - p < 3) + continue; + /* timestamp: + * big-endian 3b -> little-endian 4b */ + pp = (u_char*)×tamp; + pp[2] = *p++; + pp[1] = *p++; + pp[0] = *p++; + pp[3] = 0; + + ext = (timestamp == 0x00ffffff); + + if (fmt <= 1) { + if (b->last - p < 4) + continue; + /* size: + * big-endian 3b -> little-endian 4b + * type: + * 1b -> 1b*/ + pp = (u_char*)&h->mlen; + pp[2] = *p++; + pp[1] = *p++; + pp[0] = *p++; + pp[3] = 0; + h->type = *(uint8_t*)p++; + + if (fmt == 0) { + if (b->last - p < 4) + continue; + /* stream: + * little-endian 4b -> little-endian 4b */ + pp = (u_char*)&h->msid; + pp[0] = *p++; + pp[1] = *p++; + pp[2] = *p++; + pp[3] = *p++; + } + } + } + + /* extended header */ + if (ext) { + if (b->last - p < 4) + continue; + pp = (u_char*)×tamp; + pp[3] = *p++; + pp[2] = *p++; + pp[1] = *p++; + pp[0] = *p++; + } + + if (st->len == 0) { + /* Messages with type=3 should + * never have ext timestamp field + * according to standard. + * However that's not always the case + * in real life */ + st->ext = (ext && cscf->publish_time_fix); + if (fmt) { + st->dtime = timestamp; + } else { + h->timestamp = timestamp; + st->dtime = 0; + } + } + + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, c->log, 0, + "RTMP mheader fmt=%d %s (%d) " + "time=%uD+%uD mlen=%D len=%D msid=%D", + (int)fmt, ngx_rtmp_message_type(h->type), (int)h->type, + h->timestamp, st->dtime, h->mlen, st->len, h->msid); + + /* header done */ + b->pos = p; + + if (h->mlen > cscf->max_message) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "too big message: %uz", cscf->max_message); + ngx_rtmp_finalize_session(s); + return; + } + } + + size = b->last - b->pos; + fsize = h->mlen - st->len; + + if (size < ngx_min(fsize, s->in_chunk_size)) + continue; + + /* buffer is ready */ + + if (fsize > s->in_chunk_size) { + /* collect fragmented chunks */ + st->len += s->in_chunk_size; + b->last = b->pos + s->in_chunk_size; + old_pos = b->last; + old_size = size - s->in_chunk_size; + + } else { + /* handle! */ + head = st->in->next; + st->in->next = NULL; + b->last = b->pos + fsize; + old_pos = b->last; + old_size = size - fsize; + st->len = 0; + h->timestamp += st->dtime; + + if (ngx_rtmp_receive_message(s, h, head) != NGX_OK) { + ngx_rtmp_finalize_session(s); + return; + } + + if (s->in_chunk_size_changing) { + /* copy old data to a new buffer */ + if (!old_size) { + ngx_rtmp_finalize_set_chunk_size(s); + } + + } else { + /* add used bufs to stream #0 */ + st0 = &s->in_streams[0]; + st->in->next = st0->in; + st0->in = head; + st->in = NULL; + } + } + + s->in_csid = 0; + } +} + + +static void +ngx_rtmp_send(ngx_event_t *wev) +{ + ngx_connection_t *c; + ngx_rtmp_session_t *s; + ngx_int_t n; + ngx_rtmp_core_srv_conf_t *cscf; + + c = wev->data; + s = c->data; + + if (c->destroyed) { + return; + } + + if (wev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "client timed out"); + c->timedout = 1; + ngx_rtmp_finalize_session(s); + return; + } + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + if (s->out_chain == NULL && s->out_pos != s->out_last) { + s->out_chain = s->out[s->out_pos]; + s->out_bpos = s->out_chain->buf->pos; + } + + while (s->out_chain) { + n = c->send(c, s->out_bpos, s->out_chain->buf->last - s->out_bpos); + + if (n == NGX_AGAIN || n == 0) { + ngx_add_timer(c->write, s->timeout); + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + return; + } + + if (n < 0) { + ngx_rtmp_finalize_session(s); + return; + } + + s->out_bytes += n; + s->ping_reset = 1; + ngx_rtmp_update_bandwidth(&ngx_rtmp_bw_out, n); + s->out_bpos += n; + if (s->out_bpos == s->out_chain->buf->last) { + s->out_chain = s->out_chain->next; + if (s->out_chain == NULL) { + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos]); + ++s->out_pos; + s->out_pos %= s->out_queue; + if (s->out_pos == s->out_last) { + break; + } + s->out_chain = s->out[s->out_pos]; + } + s->out_bpos = s->out_chain->buf->pos; + } + } + + if (wev->active) { + ngx_del_event(wev, NGX_WRITE_EVENT, 0); + } + + ngx_event_process_posted((ngx_cycle_t *) ngx_cycle, &s->posted_dry_events); +} + + +void +ngx_rtmp_prepare_message(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_rtmp_header_t *lh, ngx_chain_t *out) +{ + ngx_chain_t *l; + u_char *p, *pp; + ngx_int_t hsize, thsize, nbufs; + uint32_t mlen, timestamp, ext_timestamp; + static uint8_t hdrsize[] = { 12, 8, 4, 1 }; + u_char th[7]; + ngx_rtmp_core_srv_conf_t *cscf; + uint8_t fmt; + ngx_connection_t *c; + + c = s->connection; + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (h->csid >= (uint32_t)cscf->max_streams) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "RTMP out chunk stream too big: %D >= %D", + h->csid, cscf->max_streams); + ngx_rtmp_finalize_session(s); + return; + } + + /* detect packet size */ + mlen = 0; + nbufs = 0; + for(l = out; l; l = l->next) { + mlen += (l->buf->last - l->buf->pos); + ++nbufs; + } + + fmt = 0; + if (lh && lh->csid && h->msid == lh->msid) { + ++fmt; + if (h->type == lh->type && mlen && mlen == lh->mlen) { + ++fmt; + if (h->timestamp == lh->timestamp) { + ++fmt; + } + } + timestamp = h->timestamp - lh->timestamp; + } else { + timestamp = h->timestamp; + } + + /*if (lh) { + *lh = *h; + lh->mlen = mlen; + }*/ + + hsize = hdrsize[fmt]; + + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP prep %s (%d) fmt=%d csid=%uD timestamp=%uD " + "mlen=%uD msid=%uD nbufs=%d", + ngx_rtmp_message_type(h->type), (int)h->type, (int)fmt, + h->csid, timestamp, mlen, h->msid, nbufs); + + ext_timestamp = 0; + if (timestamp >= 0x00ffffff) { + ext_timestamp = timestamp; + timestamp = 0x00ffffff; + hsize += 4; + } + + if (h->csid >= 64) { + ++hsize; + if (h->csid >= 320) { + ++hsize; + } + } + + /* fill initial header */ + out->buf->pos -= hsize; + p = out->buf->pos; + + /* basic header */ + *p = (fmt << 6); + if (h->csid >= 2 && h->csid <= 63) { + *p++ |= (((uint8_t)h->csid) & 0x3f); + } else if (h->csid >= 64 && h->csid < 320) { + ++p; + *p++ = (uint8_t)(h->csid - 64); + } else { + *p++ |= 1; + *p++ = (uint8_t)(h->csid - 64); + *p++ = (uint8_t)((h->csid - 64) >> 8); + } + + /* create fmt3 header for successive fragments */ + thsize = p - out->buf->pos; + ngx_memcpy(th, out->buf->pos, thsize); + th[0] |= 0xc0; + + /* message header */ + if (fmt <= 2) { + pp = (u_char*)×tamp; + *p++ = pp[2]; + *p++ = pp[1]; + *p++ = pp[0]; + if (fmt <= 1) { + pp = (u_char*)&mlen; + *p++ = pp[2]; + *p++ = pp[1]; + *p++ = pp[0]; + *p++ = h->type; + if (fmt == 0) { + pp = (u_char*)&h->msid; + *p++ = pp[0]; + *p++ = pp[1]; + *p++ = pp[2]; + *p++ = pp[3]; + } + } + } + + /* extended header */ + if (ext_timestamp) { + pp = (u_char*)&ext_timestamp; + *p++ = pp[3]; + *p++ = pp[2]; + *p++ = pp[1]; + *p++ = pp[0]; + + /* This CONTRADICTS the standard + * but that's the way flash client + * wants data to be encoded; + * ffmpeg complains */ + if (cscf->play_time_fix) { + ngx_memcpy(&th[thsize], p - 4, 4); + thsize += 4; + } + } + + /* append headers to successive fragments */ + for(out = out->next; out; out = out->next) { + out->buf->pos -= thsize; + ngx_memcpy(out->buf->pos, th, thsize); + } +} + + +ngx_int_t +ngx_rtmp_send_message(ngx_rtmp_session_t *s, ngx_chain_t *out, + ngx_uint_t priority) +{ + ngx_uint_t nmsg; + + nmsg = (s->out_last - s->out_pos) % s->out_queue + 1; + + if (priority > 3) { + priority = 3; + } + + /* drop packet? + * Note we always leave 1 slot free */ + if (nmsg + priority * s->out_queue / 4 >= s->out_queue) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP drop message bufs=%ui, priority=%ui", + nmsg, priority); + return NGX_AGAIN; + } + + s->out[s->out_last++] = out; + s->out_last %= s->out_queue; + + ngx_rtmp_acquire_shared_chain(out); + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP send nmsg=%ui, priority=%ui #%ui", + nmsg, priority, s->out_last); + + if (priority && s->out_buffer && nmsg < s->out_cork) { + return NGX_OK; + } + + if (!s->connection->write->active) { + ngx_rtmp_send(s->connection->write); + /*return ngx_add_event(s->connection->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT);*/ + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_receive_message(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_array_t *evhs; + size_t n; + ngx_rtmp_handler_pt *evh; + + cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); + +#ifdef NGX_DEBUG + { + int nbufs; + ngx_chain_t *ch; + + for(nbufs = 1, ch = in; + ch->next; + ch = ch->next, ++nbufs); + + ngx_log_debug7(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP recv %s (%d) csid=%D timestamp=%D " + "mlen=%D msid=%D nbufs=%d", + ngx_rtmp_message_type(h->type), (int)h->type, + h->csid, h->timestamp, h->mlen, h->msid, nbufs); + } +#endif + + if (h->type > NGX_RTMP_MSG_MAX) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "unexpected RTMP message type: %d", (int)h->type); + return NGX_OK; + } + + evhs = &cmcf->events[h->type]; + evh = evhs->elts; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "nhandlers: %d", evhs->nelts); + + for(n = 0; n < evhs->nelts; ++n, ++evh) { + if (!evh) { + continue; + } + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "calling handler %d", n); + + switch ((*evh)(s, h, in)) { + case NGX_ERROR: + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handler %d failed", n); + return NGX_ERROR; + case NGX_DONE: + return NGX_OK; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_set_chunk_size(ngx_rtmp_session_t *s, ngx_uint_t size) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_chain_t *li, *fli, *lo, *flo; + ngx_buf_t *bi, *bo; + ngx_int_t n; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "setting chunk_size=%ui", size); + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + s->in_old_pool = s->in_pool; + s->in_chunk_size = size; + s->in_pool = ngx_create_pool(4096, s->connection->log); + + /* copy existing chunk data */ + if (s->in_old_pool) { + s->in_chunk_size_changing = 1; + s->in_streams[0].in = NULL; + + for(n = 1; n < cscf->max_streams; ++n) { + /* stream buffer is circular + * for all streams except for the current one + * (which caused this chunk size change); + * we can simply ignore it */ + li = s->in_streams[n].in; + if (li == NULL || li->next == NULL) { + s->in_streams[n].in = NULL; + continue; + } + /* move from last to the first */ + li = li->next; + fli = li; + lo = ngx_rtmp_alloc_in_buf(s); + if (lo == NULL) { + return NGX_ERROR; + } + flo = lo; + for ( ;; ) { + bi = li->buf; + bo = lo->buf; + + if (bo->end - bo->last >= bi->last - bi->pos) { + bo->last = ngx_cpymem(bo->last, bi->pos, + bi->last - bi->pos); + li = li->next; + if (li == fli) { + lo->next = flo; + s->in_streams[n].in = lo; + break; + } + continue; + } + + bi->pos += (ngx_cpymem(bo->last, bi->pos, + bo->end - bo->last) - bo->last); + lo->next = ngx_rtmp_alloc_in_buf(s); + lo = lo->next; + if (lo == NULL) { + return NGX_ERROR; + } + } + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_finalize_set_chunk_size(ngx_rtmp_session_t *s) +{ + if (s->in_chunk_size_changing && s->in_old_pool) { + ngx_destroy_pool(s->in_old_pool); + s->in_old_pool = NULL; + s->in_chunk_size_changing = 0; + } + return NGX_OK; +} + + diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_handshake.c b/debian/modules/nginx-rtmp/ngx_rtmp_handshake.c new file mode 100644 index 0000000..409d9a0 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_handshake.c @@ -0,0 +1,631 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" + +#include +#include + + +static void ngx_rtmp_handshake_send(ngx_event_t *wev); +static void ngx_rtmp_handshake_recv(ngx_event_t *rev); +static void ngx_rtmp_handshake_done(ngx_rtmp_session_t *s); + + +/* RTMP handshake : + * + * =peer1= =peer2= + * challenge ----> (.....[digest1]......) ----> 1537 bytes + * response <---- (...........[digest2]) <---- 1536 bytes + * + * + * - both packets contain random bytes except for digests + * - digest1 position is calculated on random packet bytes + * - digest2 is always at the end of the packet + * + * digest1: HMAC_SHA256(packet, peer1_partial_key) + * digest2: HMAC_SHA256(packet, HMAC_SHA256(digest1, peer2_full_key)) + */ + + +/* Handshake keys */ +static u_char +ngx_rtmp_server_key[] = { + 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', + 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ', + 'S', 'e', 'r', 'v', 'e', 'r', ' ', + '0', '0', '1', + + 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, + 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, + 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE +}; + + +static u_char +ngx_rtmp_client_key[] = { + 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ', + 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', + '0', '0', '1', + + 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, + 0x02, 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, + 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE +}; + + +static const u_char +ngx_rtmp_server_version[4] = { + 0x0D, 0x0E, 0x0A, 0x0D +}; + + +static const u_char +ngx_rtmp_client_version[4] = { + 0x0C, 0x00, 0x0D, 0x0E +}; + + +#define NGX_RTMP_HANDSHAKE_KEYLEN SHA256_DIGEST_LENGTH +#define NGX_RTMP_HANDSHAKE_BUFSIZE 1537 + + +#define NGX_RTMP_HANDSHAKE_SERVER_RECV_CHALLENGE 1 +#define NGX_RTMP_HANDSHAKE_SERVER_SEND_CHALLENGE 2 +#define NGX_RTMP_HANDSHAKE_SERVER_SEND_RESPONSE 3 +#define NGX_RTMP_HANDSHAKE_SERVER_RECV_RESPONSE 4 +#define NGX_RTMP_HANDSHAKE_SERVER_DONE 5 + + +#define NGX_RTMP_HANDSHAKE_CLIENT_SEND_CHALLENGE 6 +#define NGX_RTMP_HANDSHAKE_CLIENT_RECV_CHALLENGE 7 +#define NGX_RTMP_HANDSHAKE_CLIENT_RECV_RESPONSE 8 +#define NGX_RTMP_HANDSHAKE_CLIENT_SEND_RESPONSE 9 +#define NGX_RTMP_HANDSHAKE_CLIENT_DONE 10 + + +static ngx_str_t ngx_rtmp_server_full_key + = { sizeof(ngx_rtmp_server_key), ngx_rtmp_server_key }; +static ngx_str_t ngx_rtmp_server_partial_key + = { 36, ngx_rtmp_server_key }; + +static ngx_str_t ngx_rtmp_client_full_key + = { sizeof(ngx_rtmp_client_key), ngx_rtmp_client_key }; +static ngx_str_t ngx_rtmp_client_partial_key + = { 30, ngx_rtmp_client_key }; + + +static ngx_int_t +ngx_rtmp_make_digest(ngx_str_t *key, ngx_buf_t *src, + u_char *skip, u_char *dst, ngx_log_t *log) +{ + static HMAC_CTX *hmac; + unsigned int len; + + if (hmac == NULL) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + static HMAC_CTX shmac; + hmac = &shmac; + HMAC_CTX_init(hmac); +#else + hmac = HMAC_CTX_new(); + if (hmac == NULL) { + return NGX_ERROR; + } +#endif + } + + HMAC_Init_ex(hmac, key->data, key->len, EVP_sha256(), NULL); + + if (skip && src->pos <= skip && skip <= src->last) { + if (skip != src->pos) { + HMAC_Update(hmac, src->pos, skip - src->pos); + } + if (src->last != skip + NGX_RTMP_HANDSHAKE_KEYLEN) { + HMAC_Update(hmac, skip + NGX_RTMP_HANDSHAKE_KEYLEN, + src->last - skip - NGX_RTMP_HANDSHAKE_KEYLEN); + } + } else { + HMAC_Update(hmac, src->pos, src->last - src->pos); + } + + HMAC_Final(hmac, dst, &len); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_find_digest(ngx_buf_t *b, ngx_str_t *key, size_t base, ngx_log_t *log) +{ + size_t n, offs; + u_char digest[NGX_RTMP_HANDSHAKE_KEYLEN]; + u_char *p; + + offs = 0; + for (n = 0; n < 4; ++n) { + offs += b->pos[base + n]; + } + offs = (offs % 728) + base + 4; + p = b->pos + offs; + + if (ngx_rtmp_make_digest(key, b, p, digest, log) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_memcmp(digest, p, NGX_RTMP_HANDSHAKE_KEYLEN) == 0) { + return offs; + } + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_write_digest(ngx_buf_t *b, ngx_str_t *key, size_t base, + ngx_log_t *log) +{ + size_t n, offs; + u_char *p; + + offs = 0; + for (n = 8; n < 12; ++n) { + offs += b->pos[base + n]; + } + offs = (offs % 728) + base + 12; + p = b->pos + offs; + + if (ngx_rtmp_make_digest(key, b, p, p, log) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static void +ngx_rtmp_fill_random_buffer(ngx_buf_t *b) +{ + for (; b->last != b->end; ++b->last) { + *b->last = (u_char) rand(); + } +} + + +static ngx_buf_t * +ngx_rtmp_alloc_handshake_buffer(ngx_rtmp_session_t *s) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_chain_t *cl; + ngx_buf_t *b; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: allocating buffer"); + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + if (cscf->free_hs) { + cl = cscf->free_hs; + b = cl->buf; + cscf->free_hs = cl->next; + ngx_free_chain(cscf->pool, cl); + + } else { + b = ngx_pcalloc(cscf->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NULL; + } + b->memory = 1; + b->start = ngx_pcalloc(cscf->pool, NGX_RTMP_HANDSHAKE_BUFSIZE); + if (b->start == NULL) { + return NULL; + } + b->end = b->start + NGX_RTMP_HANDSHAKE_BUFSIZE; + } + + b->pos = b->last = b->start; + + return b; +} + + +void +ngx_rtmp_free_handshake_buffers(ngx_rtmp_session_t *s) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_chain_t *cl; + + if (s->hs_buf == NULL) { + return; + } + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + cl = ngx_alloc_chain_link(cscf->pool); + if (cl == NULL) { + return; + } + cl->buf = s->hs_buf; + cl->next = cscf->free_hs; + cscf->free_hs = cl; + s->hs_buf = NULL; +} + + +static ngx_int_t +ngx_rtmp_handshake_create_challenge(ngx_rtmp_session_t *s, + const u_char version[4], ngx_str_t *key) +{ + ngx_buf_t *b; + + b = s->hs_buf; + b->last = b->pos = b->start; + *b->last++ = '\x03'; + b->last = ngx_rtmp_rcpymem(b->last, &s->epoch, 4); + b->last = ngx_cpymem(b->last, version, 4); + ngx_rtmp_fill_random_buffer(b); + ++b->pos; + if (ngx_rtmp_write_digest(b, key, 0, s->connection->log) != NGX_OK) { + return NGX_ERROR; + } + --b->pos; + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_handshake_parse_challenge(ngx_rtmp_session_t *s, + ngx_str_t *peer_key, ngx_str_t *key) +{ + ngx_buf_t *b; + u_char *p; + ngx_int_t offs; + + b = s->hs_buf; + if (*b->pos != '\x03') { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "handshake: unexpected RTMP version: %i", + (ngx_int_t)*b->pos); + return NGX_ERROR; + } + ++b->pos; + s->peer_epoch = 0; + ngx_rtmp_rmemcpy(&s->peer_epoch, b->pos, 4); + + p = b->pos + 4; + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: peer version=%i.%i.%i.%i epoch=%uD", + (ngx_int_t)p[3], (ngx_int_t)p[2], + (ngx_int_t)p[1], (ngx_int_t)p[0], + (uint32_t)s->peer_epoch); + if (*(uint32_t *)p == 0) { + s->hs_old = 1; + return NGX_OK; + } + + offs = ngx_rtmp_find_digest(b, peer_key, 772, s->connection->log); + if (offs == NGX_ERROR) { + offs = ngx_rtmp_find_digest(b, peer_key, 8, s->connection->log); + } + if (offs == NGX_ERROR) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "handshake: digest not found"); + s->hs_old = 1; + return NGX_OK; + } + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: digest found at pos=%i", offs); + b->pos += offs; + b->last = b->pos + NGX_RTMP_HANDSHAKE_KEYLEN; + s->hs_digest = ngx_palloc(s->connection->pool, NGX_RTMP_HANDSHAKE_KEYLEN); + if (ngx_rtmp_make_digest(key, b, NULL, s->hs_digest, s->connection->log) + != NGX_OK) + { + return NGX_ERROR; + } + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_handshake_create_response(ngx_rtmp_session_t *s) +{ + ngx_buf_t *b; + u_char *p; + ngx_str_t key; + + b = s->hs_buf; + b->pos = b->last = b->start + 1; + ngx_rtmp_fill_random_buffer(b); + if (s->hs_digest) { + p = b->last - NGX_RTMP_HANDSHAKE_KEYLEN; + key.data = s->hs_digest; + key.len = NGX_RTMP_HANDSHAKE_KEYLEN; + if (ngx_rtmp_make_digest(&key, b, p, p, s->connection->log) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static void +ngx_rtmp_handshake_done(ngx_rtmp_session_t *s) +{ + ngx_rtmp_free_handshake_buffers(s); + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: done"); + + if (ngx_rtmp_fire_event(s, NGX_RTMP_HANDSHAKE_DONE, + NULL, NULL) != NGX_OK) + { + ngx_rtmp_finalize_session(s); + return; + } + + ngx_rtmp_cycle(s); +} + + +static void +ngx_rtmp_handshake_recv(ngx_event_t *rev) +{ + ssize_t n; + ngx_connection_t *c; + ngx_rtmp_session_t *s; + ngx_buf_t *b; + + c = rev->data; + s = c->data; + + if (c->destroyed) { + return; + } + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "handshake: recv: client timed out"); + c->timedout = 1; + ngx_rtmp_finalize_session(s); + return; + } + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + b = s->hs_buf; + + while (b->last != b->end) { + n = c->recv(c, b->last, b->end - b->last); + + if (n == NGX_ERROR || n == 0) { + ngx_rtmp_finalize_session(s); + return; + } + + if (n == NGX_AGAIN) { + ngx_add_timer(rev, s->timeout); + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + return; + } + + b->last += n; + } + + if (rev->active) { + ngx_del_event(rev, NGX_READ_EVENT, 0); + } + + ++s->hs_stage; + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: stage %ui", s->hs_stage); + + switch (s->hs_stage) { + case NGX_RTMP_HANDSHAKE_SERVER_SEND_CHALLENGE: + if (ngx_rtmp_handshake_parse_challenge(s, + &ngx_rtmp_client_partial_key, + &ngx_rtmp_server_full_key) != NGX_OK) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "handshake: error parsing challenge"); + ngx_rtmp_finalize_session(s); + return; + } + if (s->hs_old) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: old-style challenge"); + s->hs_buf->pos = s->hs_buf->start; + s->hs_buf->last = s->hs_buf->end; + } else if (ngx_rtmp_handshake_create_challenge(s, + ngx_rtmp_server_version, + &ngx_rtmp_server_partial_key) != NGX_OK) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "handshake: error creating challenge"); + ngx_rtmp_finalize_session(s); + return; + } + ngx_rtmp_handshake_send(c->write); + break; + + case NGX_RTMP_HANDSHAKE_SERVER_DONE: + ngx_rtmp_handshake_done(s); + break; + + case NGX_RTMP_HANDSHAKE_CLIENT_RECV_RESPONSE: + if (ngx_rtmp_handshake_parse_challenge(s, + &ngx_rtmp_server_partial_key, + &ngx_rtmp_client_full_key) != NGX_OK) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "handshake: error parsing challenge"); + ngx_rtmp_finalize_session(s); + return; + } + s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start + 1; + ngx_rtmp_handshake_recv(c->read); + break; + + case NGX_RTMP_HANDSHAKE_CLIENT_SEND_RESPONSE: + if (ngx_rtmp_handshake_create_response(s) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "handshake: response error"); + ngx_rtmp_finalize_session(s); + return; + } + ngx_rtmp_handshake_send(c->write); + break; + } +} + + +static void +ngx_rtmp_handshake_send(ngx_event_t *wev) +{ + ngx_int_t n; + ngx_connection_t *c; + ngx_rtmp_session_t *s; + ngx_buf_t *b; + + c = wev->data; + s = c->data; + + if (c->destroyed) { + return; + } + + if (wev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "handshake: send: client timed out"); + c->timedout = 1; + ngx_rtmp_finalize_session(s); + return; + } + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + b = s->hs_buf; + + while(b->pos != b->last) { + n = c->send(c, b->pos, b->last - b->pos); + + if (n == NGX_ERROR) { + ngx_rtmp_finalize_session(s); + return; + } + + if (n == NGX_AGAIN || n == 0) { + ngx_add_timer(c->write, s->timeout); + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + return; + } + + b->pos += n; + } + + if (wev->active) { + ngx_del_event(wev, NGX_WRITE_EVENT, 0); + } + + ++s->hs_stage; + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: stage %ui", s->hs_stage); + + switch (s->hs_stage) { + case NGX_RTMP_HANDSHAKE_SERVER_SEND_RESPONSE: + if (s->hs_old) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: old-style response"); + s->hs_buf->pos = s->hs_buf->start + 1; + s->hs_buf->last = s->hs_buf->end; + } else if (ngx_rtmp_handshake_create_response(s) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "handshake: response error"); + ngx_rtmp_finalize_session(s); + return; + } + ngx_rtmp_handshake_send(wev); + break; + + case NGX_RTMP_HANDSHAKE_SERVER_RECV_RESPONSE: + s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start + 1; + ngx_rtmp_handshake_recv(c->read); + break; + + case NGX_RTMP_HANDSHAKE_CLIENT_RECV_CHALLENGE: + s->hs_buf->pos = s->hs_buf->last = s->hs_buf->start; + ngx_rtmp_handshake_recv(c->read); + break; + + case NGX_RTMP_HANDSHAKE_CLIENT_DONE: + ngx_rtmp_handshake_done(s); + break; + } +} + + +void +ngx_rtmp_handshake(ngx_rtmp_session_t *s) +{ + ngx_connection_t *c; + + c = s->connection; + c->read->handler = ngx_rtmp_handshake_recv; + c->write->handler = ngx_rtmp_handshake_send; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: start server handshake"); + + s->hs_buf = ngx_rtmp_alloc_handshake_buffer(s); + s->hs_stage = NGX_RTMP_HANDSHAKE_SERVER_RECV_CHALLENGE; + + ngx_rtmp_handshake_recv(c->read); +} + + +void +ngx_rtmp_client_handshake(ngx_rtmp_session_t *s, unsigned async) +{ + ngx_connection_t *c; + + c = s->connection; + c->read->handler = ngx_rtmp_handshake_recv; + c->write->handler = ngx_rtmp_handshake_send; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "handshake: start client handshake"); + + s->hs_buf = ngx_rtmp_alloc_handshake_buffer(s); + s->hs_stage = NGX_RTMP_HANDSHAKE_CLIENT_SEND_CHALLENGE; + + if (ngx_rtmp_handshake_create_challenge(s, + ngx_rtmp_client_version, + &ngx_rtmp_client_partial_key) != NGX_OK) + { + ngx_rtmp_finalize_session(s); + return; + } + + if (async) { + ngx_add_timer(c->write, s->timeout); + if (ngx_handle_write_event(c->write, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + return; + } + + ngx_rtmp_handshake_send(c->write); +} + diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_init.c b/debian/modules/nginx-rtmp/ngx_rtmp_init.c new file mode 100644 index 0000000..97c7e9a --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_init.c @@ -0,0 +1,329 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_proxy_protocol.h" + + +static void ngx_rtmp_close_connection(ngx_connection_t *c); +static u_char * ngx_rtmp_log_error(ngx_log_t *log, u_char *buf, size_t len); + + +void +ngx_rtmp_init_connection(ngx_connection_t *c) +{ + ngx_uint_t i; + ngx_rtmp_port_t *port; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_rtmp_in_addr_t *addr; + ngx_rtmp_session_t *s; + ngx_rtmp_addr_conf_t *addr_conf; + ngx_int_t unix_socket; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; + ngx_rtmp_in6_addr_t *addr6; +#endif + + ++ngx_rtmp_naccepted; + + /* find the server configuration for the address:port */ + + /* AF_INET only */ + + port = c->listening->servers; + unix_socket = 0; + + if (port->naddrs > 1) { + + /* + * There are several addresses on this port and one of them + * is the "*:port" wildcard so getsockname() is needed to determine + * the server address. + * + * AcceptEx() already gave this address. + */ + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + ngx_rtmp_close_connection(c); + return; + } + + sa = c->local_sockaddr; + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + + addr6 = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { + break; + } + } + + addr_conf = &addr6[i].conf; + + break; +#endif + + case AF_UNIX: + unix_socket = 1; + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + + addr = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (addr[i].addr == sin->sin_addr.s_addr) { + break; + } + } + + addr_conf = &addr[i].conf; + + break; + } + + } else { + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + addr6 = port->addrs; + addr_conf = &addr6[0].conf; + break; +#endif + + case AF_UNIX: + unix_socket = 1; + + default: /* AF_INET */ + addr = port->addrs; + addr_conf = &addr[0].conf; + break; + } + } + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client connected '%V'", + c->number, &c->addr_text); + + s = ngx_rtmp_init_session(c, addr_conf); + if (s == NULL) { + return; + } + + /* only auto-pushed connections are + * done through unix socket */ + + s->auto_pushed = unix_socket; + + if (addr_conf->proxy_protocol) { + ngx_rtmp_proxy_protocol(s); + + } else { + ngx_rtmp_handshake(s); + } +} + + +ngx_rtmp_session_t * +ngx_rtmp_init_session(ngx_connection_t *c, ngx_rtmp_addr_conf_t *addr_conf) +{ + ngx_rtmp_session_t *s; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_error_log_ctx_t *ctx; + + s = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_session_t) + + sizeof(ngx_chain_t *) * ((ngx_rtmp_core_srv_conf_t *) + addr_conf->ctx-> srv_conf[ngx_rtmp_core_module + .ctx_index])->out_queue); + if (s == NULL) { + ngx_rtmp_close_connection(c); + return NULL; + } + + s->main_conf = addr_conf->ctx->main_conf; + s->srv_conf = addr_conf->ctx->srv_conf; + + s->addr_text = &addr_conf->addr_text; + + c->data = s; + s->connection = c; + + ctx = ngx_palloc(c->pool, sizeof(ngx_rtmp_error_log_ctx_t)); + if (ctx == NULL) { + ngx_rtmp_close_connection(c); + return NULL; + } + + ctx->client = &c->addr_text; + ctx->session = s; + + c->log->connection = c->number; + c->log->handler = ngx_rtmp_log_error; + c->log->data = ctx; + c->log->action = NULL; + + c->log_error = NGX_ERROR_INFO; + + s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_rtmp_max_module); + if (s->ctx == NULL) { + ngx_rtmp_close_connection(c); + return NULL; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + s->out_queue = cscf->out_queue; + s->out_cork = cscf->out_cork; + s->in_streams = ngx_pcalloc(c->pool, sizeof(ngx_rtmp_stream_t) + * cscf->max_streams); + if (s->in_streams == NULL) { + ngx_rtmp_close_connection(c); + return NULL; + } + +#if (nginx_version >= 1007005) + ngx_queue_init(&s->posted_dry_events); +#endif + + s->epoch = ngx_current_msec; + s->timeout = cscf->timeout; + s->buflen = cscf->buflen; + ngx_rtmp_set_chunk_size(s, NGX_RTMP_DEFAULT_CHUNK_SIZE); + + + if (ngx_rtmp_fire_event(s, NGX_RTMP_CONNECT, NULL, NULL) != NGX_OK) { + ngx_rtmp_finalize_session(s); + return NULL; + } + + return s; +} + + +static u_char * +ngx_rtmp_log_error(ngx_log_t *log, u_char *buf, size_t len) +{ + u_char *p; + ngx_rtmp_session_t *s; + ngx_rtmp_error_log_ctx_t *ctx; + + if (log->action) { + p = ngx_snprintf(buf, len, " while %s", log->action); + len -= p - buf; + buf = p; + } + + ctx = log->data; + + p = ngx_snprintf(buf, len, ", client: %V", ctx->client); + len -= p - buf; + buf = p; + + s = ctx->session; + + if (s == NULL) { + return p; + } + + p = ngx_snprintf(buf, len, ", server: %V", s->addr_text); + len -= p - buf; + buf = p; + + return p; +} + + +static void +ngx_rtmp_close_connection(ngx_connection_t *c) +{ + ngx_pool_t *pool; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "close connection"); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, -1); +#endif + + pool = c->pool; + ngx_close_connection(c); + ngx_destroy_pool(pool); +} + + +static void +ngx_rtmp_close_session_handler(ngx_event_t *e) +{ + ngx_rtmp_session_t *s; + ngx_connection_t *c; + ngx_rtmp_core_srv_conf_t *cscf; + + s = e->data; + c = s->connection; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "close session"); + + ngx_rtmp_fire_event(s, NGX_RTMP_DISCONNECT, NULL, NULL); + + if (s->ping_evt.timer_set) { + ngx_del_timer(&s->ping_evt); + } + + if (s->in_old_pool) { + ngx_destroy_pool(s->in_old_pool); + } + + if (s->in_pool) { + ngx_destroy_pool(s->in_pool); + } + + ngx_rtmp_free_handshake_buffers(s); + + while (s->out_pos != s->out_last) { + ngx_rtmp_free_shared_chain(cscf, s->out[s->out_pos++]); + s->out_pos %= s->out_queue; + } + + ngx_rtmp_close_connection(c); +} + + +void +ngx_rtmp_finalize_session(ngx_rtmp_session_t *s) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = s->connection; + if (c->destroyed) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, c->log, 0, "finalize session"); + + c->destroyed = 1; + e = &s->close; + e->data = s; + e->handler = ngx_rtmp_close_session_handler; + e->log = c->log; + + ngx_post_event(e, &ngx_posted_events); +} + diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c new file mode 100644 index 0000000..18ebc4b --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c @@ -0,0 +1,205 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" + + +typedef struct { + ngx_int_t max_conn; + ngx_shm_zone_t *shm_zone; +} ngx_rtmp_limit_main_conf_t; + + +static ngx_str_t shm_name = ngx_string("rtmp_limit"); + + +static ngx_int_t ngx_rtmp_limit_postconfiguration(ngx_conf_t *cf); +static void *ngx_rtmp_limit_create_main_conf(ngx_conf_t *cf); + + +static ngx_command_t ngx_rtmp_limit_commands[] = { + + { ngx_string("max_connections"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_RTMP_MAIN_CONF_OFFSET, + offsetof(ngx_rtmp_limit_main_conf_t, max_conn), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_limit_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_limit_postconfiguration, /* postconfiguration */ + ngx_rtmp_limit_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_limit_module = { + NGX_MODULE_V1, + &ngx_rtmp_limit_module_ctx, /* module context */ + ngx_rtmp_limit_commands, /* module directives */ + NGX_RTMP_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_rtmp_limit_create_main_conf(ngx_conf_t *cf) +{ + ngx_rtmp_limit_main_conf_t *lmcf; + + lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_limit_main_conf_t)); + if (lmcf == NULL) { + return NULL; + } + + lmcf->max_conn = NGX_CONF_UNSET; + + return lmcf; +} + + +static ngx_int_t +ngx_rtmp_limit_connect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_limit_main_conf_t *lmcf; + ngx_slab_pool_t *shpool; + ngx_shm_zone_t *shm_zone; + uint32_t *nconn, n; + ngx_int_t rc; + + lmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_limit_module); + if (lmcf->max_conn == NGX_CONF_UNSET) { + return NGX_OK; + } + + shm_zone = lmcf->shm_zone; + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + nconn = shm_zone->data; + + ngx_shmtx_lock(&shpool->mutex); + n = ++*nconn; + ngx_shmtx_unlock(&shpool->mutex); + + rc = n > (ngx_uint_t) lmcf->max_conn ? NGX_ERROR : NGX_OK; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "limit: inc conection counter: %uD", n); + + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "limit: too many connections: %uD > %i", + n, lmcf->max_conn); + } + + return rc; +} + + +static ngx_int_t +ngx_rtmp_limit_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_limit_main_conf_t *lmcf; + ngx_slab_pool_t *shpool; + ngx_shm_zone_t *shm_zone; + uint32_t *nconn, n; + + lmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_limit_module); + if (lmcf->max_conn == NGX_CONF_UNSET) { + return NGX_OK; + } + + shm_zone = lmcf->shm_zone; + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + nconn = shm_zone->data; + + ngx_shmtx_lock(&shpool->mutex); + n = --*nconn; + ngx_shmtx_unlock(&shpool->mutex); + + (void) n; + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "limit: dec conection counter: %uD", n); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_limit_shm_init(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_slab_pool_t *shpool; + uint32_t *nconn; + + if (data) { + shm_zone->data = data; + return NGX_OK; + } + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + nconn = ngx_slab_alloc(shpool, 4); + if (nconn == NULL) { + return NGX_ERROR; + } + + *nconn = 0; + + shm_zone->data = nconn; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_limit_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_limit_main_conf_t *lmcf; + ngx_rtmp_handler_pt *h; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_CONNECT]); + *h = ngx_rtmp_limit_connect; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); + *h = ngx_rtmp_limit_disconnect; + + lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_limit_module); + if (lmcf->max_conn == NGX_CONF_UNSET) { + return NGX_OK; + } + + lmcf->shm_zone = ngx_shared_memory_add(cf, &shm_name, ngx_pagesize * 2, + &ngx_rtmp_limit_module); + if (lmcf->shm_zone == NULL) { + return NGX_ERROR; + } + + lmcf->shm_zone->init = ngx_rtmp_limit_shm_init; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_live_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_live_module.c new file mode 100644 index 0000000..5bebb9e --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_live_module.c @@ -0,0 +1,1153 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_codec_module.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_play_pt next_play; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_pause_pt next_pause; +static ngx_rtmp_stream_begin_pt next_stream_begin; +static ngx_rtmp_stream_eof_pt next_stream_eof; + + +static ngx_int_t ngx_rtmp_live_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_live_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_live_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static char *ngx_rtmp_live_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void ngx_rtmp_live_start(ngx_rtmp_session_t *s); +static void ngx_rtmp_live_stop(ngx_rtmp_session_t *s); + + +static ngx_command_t ngx_rtmp_live_commands[] = { + + { ngx_string("live"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, live), + NULL }, + + { ngx_string("stream_buckets"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, nbuckets), + NULL }, + + { ngx_string("buffer"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, buflen), + NULL }, + + { ngx_string("sync"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_live_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, sync), + NULL }, + + { ngx_string("interleave"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, interleave), + NULL }, + + { ngx_string("wait_key"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, wait_key), + NULL }, + + { ngx_string("wait_video"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, wait_video), + NULL }, + + { ngx_string("publish_notify"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, publish_notify), + NULL }, + + { ngx_string("play_restart"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, play_restart), + NULL }, + + { ngx_string("idle_streams"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, idle_streams), + NULL }, + + { ngx_string("drop_idle_publisher"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_live_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_live_app_conf_t, idle_timeout), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_live_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_live_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_live_create_app_conf, /* create app configuration */ + ngx_rtmp_live_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_live_module = { + NGX_MODULE_V1, + &ngx_rtmp_live_module_ctx, /* module context */ + ngx_rtmp_live_commands, /* module directives */ + NGX_RTMP_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_rtmp_live_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_live_app_conf_t *lacf; + + lacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_live_app_conf_t)); + if (lacf == NULL) { + return NULL; + } + + lacf->live = NGX_CONF_UNSET; + lacf->nbuckets = NGX_CONF_UNSET; + lacf->buflen = NGX_CONF_UNSET_MSEC; + lacf->sync = NGX_CONF_UNSET_MSEC; + lacf->idle_timeout = NGX_CONF_UNSET_MSEC; + lacf->interleave = NGX_CONF_UNSET; + lacf->wait_key = NGX_CONF_UNSET; + lacf->wait_video = NGX_CONF_UNSET; + lacf->publish_notify = NGX_CONF_UNSET; + lacf->play_restart = NGX_CONF_UNSET; + lacf->idle_streams = NGX_CONF_UNSET; + + return lacf; +} + + +static char * +ngx_rtmp_live_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_live_app_conf_t *prev = parent; + ngx_rtmp_live_app_conf_t *conf = child; + + ngx_conf_merge_value(conf->live, prev->live, 0); + ngx_conf_merge_value(conf->nbuckets, prev->nbuckets, 1024); + ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 0); + ngx_conf_merge_msec_value(conf->sync, prev->sync, 300); + ngx_conf_merge_msec_value(conf->idle_timeout, prev->idle_timeout, 0); + ngx_conf_merge_value(conf->interleave, prev->interleave, 0); + ngx_conf_merge_value(conf->wait_key, prev->wait_key, 1); + ngx_conf_merge_value(conf->wait_video, prev->wait_video, 0); + ngx_conf_merge_value(conf->publish_notify, prev->publish_notify, 0); + ngx_conf_merge_value(conf->play_restart, prev->play_restart, 0); + ngx_conf_merge_value(conf->idle_streams, prev->idle_streams, 1); + + conf->pool = ngx_create_pool(4096, &cf->cycle->new_log); + if (conf->pool == NULL) { + return NGX_CONF_ERROR; + } + + conf->streams = ngx_pcalloc(cf->pool, + sizeof(ngx_rtmp_live_stream_t *) * conf->nbuckets); + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_live_set_msec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + ngx_str_t *value; + ngx_msec_t *msp; + + msp = (ngx_msec_t *) (p + cmd->offset); + + value = cf->args->elts; + + if (value[1].len == sizeof("off") - 1 && + ngx_strncasecmp(value[1].data, (u_char *) "off", value[1].len) == 0) + { + *msp = 0; + return NGX_CONF_OK; + } + + return ngx_conf_set_msec_slot(cf, cmd, conf); +} + + +static ngx_rtmp_live_stream_t ** +ngx_rtmp_live_get_stream(ngx_rtmp_session_t *s, u_char *name, int create) +{ + ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_live_stream_t **stream; + size_t len; + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + if (lacf == NULL) { + return NULL; + } + + len = ngx_strlen(name); + stream = &lacf->streams[ngx_hash_key(name, len) % lacf->nbuckets]; + + for (; *stream; stream = &(*stream)->next) { + if (ngx_strcmp(name, (*stream)->name) == 0) { + return stream; + } + } + + if (!create) { + return NULL; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: create stream '%s'", name); + + if (lacf->free_streams) { + *stream = lacf->free_streams; + lacf->free_streams = lacf->free_streams->next; + } else { + *stream = ngx_palloc(lacf->pool, sizeof(ngx_rtmp_live_stream_t)); + } + ngx_memzero(*stream, sizeof(ngx_rtmp_live_stream_t)); + ngx_memcpy((*stream)->name, name, + ngx_min(sizeof((*stream)->name) - 1, len)); + (*stream)->epoch = ngx_current_msec; + + return stream; +} + + +static void +ngx_rtmp_live_idle(ngx_event_t *pev) +{ + ngx_connection_t *c; + ngx_rtmp_session_t *s; + + c = pev->data; + s = c->data; + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "live: drop idle publisher"); + + ngx_rtmp_finalize_session(s); +} + + +static void +ngx_rtmp_live_set_status(ngx_rtmp_session_t *s, ngx_chain_t *control, + ngx_chain_t **status, size_t nstatus, + unsigned active) +{ + ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_live_ctx_t *ctx, *pctx; + ngx_chain_t **cl; + ngx_event_t *e; + size_t n; + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: set active=%ui", active); + + if (ctx->active == active) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: unchanged active=%ui", active); + return; + } + + ctx->active = active; + + if (ctx->publishing) { + + /* publisher */ + + if (lacf->idle_timeout) { + e = &ctx->idle_evt; + + if (active && !ctx->idle_evt.timer_set) { + e->data = s->connection; + e->log = s->connection->log; + e->handler = ngx_rtmp_live_idle; + + ngx_add_timer(e, lacf->idle_timeout); + + } else if (!active && ctx->idle_evt.timer_set) { + ngx_del_timer(e); + } + } + + ctx->stream->active = active; + + for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { + if (pctx->publishing == 0) { + ngx_rtmp_live_set_status(pctx->session, control, status, + nstatus, active); + } + } + + return; + } + + /* subscriber */ + + if (control && ngx_rtmp_send_message(s, control, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + return; + } + + if (!ctx->silent) { + cl = status; + + for (n = 0; n < nstatus; ++n, ++cl) { + if (*cl && ngx_rtmp_send_message(s, *cl, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + return; + } + } + } + + ctx->cs[0].active = 0; + ctx->cs[0].dropped = 0; + + ctx->cs[1].active = 0; + ctx->cs[1].dropped = 0; +} + + +static void +ngx_rtmp_live_start(ngx_rtmp_session_t *s) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_live_app_conf_t *lacf; + ngx_chain_t *control; + ngx_chain_t *status[3]; + size_t n, nstatus; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + + control = ngx_rtmp_create_stream_begin(s, NGX_RTMP_MSID); + + nstatus = 0; + + if (lacf->play_restart) { + status[nstatus++] = ngx_rtmp_create_status(s, "NetStream.Play.Start", + "status", "Start live"); + status[nstatus++] = ngx_rtmp_create_sample_access(s); + } + + if (lacf->publish_notify) { + status[nstatus++] = ngx_rtmp_create_status(s, + "NetStream.Play.PublishNotify", + "status", "Start publishing"); + } + + ngx_rtmp_live_set_status(s, control, status, nstatus, 1); + + if (control) { + ngx_rtmp_free_shared_chain(cscf, control); + } + + for (n = 0; n < nstatus; ++n) { + ngx_rtmp_free_shared_chain(cscf, status[n]); + } +} + + +static void +ngx_rtmp_live_stop(ngx_rtmp_session_t *s) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_live_app_conf_t *lacf; + ngx_chain_t *control; + ngx_chain_t *status[3]; + size_t n, nstatus; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + + control = ngx_rtmp_create_stream_eof(s, NGX_RTMP_MSID); + + nstatus = 0; + + if (lacf->play_restart) { + status[nstatus++] = ngx_rtmp_create_status(s, "NetStream.Play.Stop", + "status", "Stop live"); + } + + if (lacf->publish_notify) { + status[nstatus++] = ngx_rtmp_create_status(s, + "NetStream.Play.UnpublishNotify", + "status", "Stop publishing"); + } + + ngx_rtmp_live_set_status(s, control, status, nstatus, 0); + + if (control) { + ngx_rtmp_free_shared_chain(cscf, control); + } + + for (n = 0; n < nstatus; ++n) { + ngx_rtmp_free_shared_chain(cscf, status[n]); + } +} + + +static ngx_int_t +ngx_rtmp_live_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) +{ + ngx_rtmp_live_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + + if (ctx == NULL || ctx->stream == NULL || !ctx->publishing) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: stream_begin"); + + ngx_rtmp_live_start(s); + +next: + return next_stream_begin(s, v); +} + + +static ngx_int_t +ngx_rtmp_live_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_eof_t *v) +{ + ngx_rtmp_live_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + + if (ctx == NULL || ctx->stream == NULL || !ctx->publishing) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: stream_eof"); + + ngx_rtmp_live_stop(s); + +next: + return next_stream_eof(s, v); +} + + +static void +ngx_rtmp_live_join(ngx_rtmp_session_t *s, u_char *name, unsigned publisher) +{ + ngx_rtmp_live_ctx_t *ctx; + ngx_rtmp_live_stream_t **stream; + ngx_rtmp_live_app_conf_t *lacf; + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + if (lacf == NULL) { + return; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (ctx && ctx->stream) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: already joined"); + return; + } + + if (ctx == NULL) { + ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_live_ctx_t)); + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_live_module); + } + + ngx_memzero(ctx, sizeof(*ctx)); + + ctx->session = s; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: join '%s'", name); + + stream = ngx_rtmp_live_get_stream(s, name, publisher || lacf->idle_streams); + + if (stream == NULL || + !(publisher || (*stream)->publishing || lacf->idle_streams)) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "live: stream not found"); + + ngx_rtmp_send_status(s, "NetStream.Play.StreamNotFound", "error", + "No such stream"); + + ngx_rtmp_finalize_session(s); + + return; + } + + if (publisher) { + if ((*stream)->publishing) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "live: already publishing"); + + ngx_rtmp_send_status(s, "NetStream.Publish.BadName", "error", + "Already publishing"); + + return; + } + + (*stream)->publishing = 1; + } + + ctx->stream = *stream; + ctx->publishing = publisher; + ctx->next = (*stream)->ctx; + + (*stream)->ctx = ctx; + + if (lacf->buflen) { + s->out_buffer = 1; + } + + ctx->cs[0].csid = NGX_RTMP_CSID_VIDEO; + ctx->cs[1].csid = NGX_RTMP_CSID_AUDIO; + + if (!ctx->publishing && ctx->stream->active) { + ngx_rtmp_live_start(s); + } +} + + +static ngx_int_t +ngx_rtmp_live_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + ngx_rtmp_session_t *ss; + ngx_rtmp_live_ctx_t *ctx, **cctx, *pctx; + ngx_rtmp_live_stream_t **stream; + ngx_rtmp_live_app_conf_t *lacf; + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + if (lacf == NULL) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (ctx == NULL) { + goto next; + } + + if (ctx->stream == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: not joined"); + goto next; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: leave '%s'", ctx->stream->name); + + if (ctx->stream->publishing && ctx->publishing) { + ctx->stream->publishing = 0; + } + + for (cctx = &ctx->stream->ctx; *cctx; cctx = &(*cctx)->next) { + if (*cctx == ctx) { + *cctx = ctx->next; + break; + } + } + + if (ctx->publishing || ctx->stream->active) { + ngx_rtmp_live_stop(s); + } + + if (ctx->publishing) { + ngx_rtmp_send_status(s, "NetStream.Unpublish.Success", + "status", "Stop publishing"); + if (!lacf->idle_streams) { + for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { + if (pctx->publishing == 0) { + ss = pctx->session; + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: no publisher"); + ngx_rtmp_finalize_session(ss); + } + } + } + } + + if (ctx->stream->ctx) { + ctx->stream = NULL; + goto next; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: delete empty stream '%s'", + ctx->stream->name); + + stream = ngx_rtmp_live_get_stream(s, ctx->stream->name, 0); + if (stream == NULL) { + goto next; + } + *stream = (*stream)->next; + + ctx->stream->next = lacf->free_streams; + lacf->free_streams = ctx->stream; + ctx->stream = NULL; + + if (!ctx->silent && !ctx->publishing && !lacf->play_restart) { + ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stop live"); + } + +next: + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_live_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v) +{ + ngx_rtmp_live_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + + if (ctx == NULL || ctx->stream == NULL) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: pause=%i timestamp=%f", + (ngx_int_t) v->pause, v->position); + + if (v->pause) { + if (ngx_rtmp_send_status(s, "NetStream.Pause.Notify", "status", + "Paused live") + != NGX_OK) + { + return NGX_ERROR; + } + + ctx->paused = 1; + + ngx_rtmp_live_stop(s); + + } else { + if (ngx_rtmp_send_status(s, "NetStream.Unpause.Notify", "status", + "Unpaused live") + != NGX_OK) + { + return NGX_ERROR; + } + + ctx->paused = 0; + + ngx_rtmp_live_start(s); + } + +next: + return next_pause(s, v); +} + +static ngx_int_t +ngx_rtmp_live_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_live_ctx_t *ctx, *pctx; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_chain_t *header, *coheader, *meta, + *apkt, *aapkt, *acopkt, *rpkt; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_session_t *ss; + ngx_rtmp_header_t ch, lh, clh; + ngx_int_t rc, mandatory, dummy_audio; + ngx_uint_t prio; + ngx_uint_t peers; + ngx_uint_t meta_version; + ngx_uint_t csidx; + uint32_t delta; + ngx_rtmp_live_chunk_stream_t *cs; +#ifdef NGX_DEBUG + const char *type_s; + + type_s = (h->type == NGX_RTMP_MSG_VIDEO ? "video" : "audio"); +#endif + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + if (lacf == NULL) { + return NGX_ERROR; + } + + if (!lacf->live || in == NULL || in->buf == NULL) { + return NGX_OK; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (ctx == NULL || ctx->stream == NULL) { + return NGX_OK; + } + + if (ctx->publishing == 0) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: %s from non-publisher", type_s); + return NGX_OK; + } + + if (!ctx->stream->active) { + ngx_rtmp_live_start(s); + } + + if (ctx->idle_evt.timer_set) { + ngx_add_timer(&ctx->idle_evt, lacf->idle_timeout); + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: %s packet timestamp=%uD", + type_s, h->timestamp); + + s->current_time = h->timestamp; + + peers = 0; + apkt = NULL; + aapkt = NULL; + acopkt = NULL; + header = NULL; + coheader = NULL; + meta = NULL; + meta_version = 0; + mandatory = 0; + + prio = (h->type == NGX_RTMP_MSG_VIDEO ? + ngx_rtmp_get_video_frame_type(in) : 0); + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + csidx = !(lacf->interleave || h->type == NGX_RTMP_MSG_VIDEO); + + cs = &ctx->cs[csidx]; + + ngx_memzero(&ch, sizeof(ch)); + + ch.timestamp = h->timestamp; + ch.msid = NGX_RTMP_MSID; + ch.csid = cs->csid; + ch.type = h->type; + + lh = ch; + + if (cs->active) { + lh.timestamp = cs->timestamp; + } + + clh = lh; + clh.type = (h->type == NGX_RTMP_MSG_AUDIO ? NGX_RTMP_MSG_VIDEO : + NGX_RTMP_MSG_AUDIO); + + cs->active = 1; + cs->timestamp = ch.timestamp; + + delta = ch.timestamp - lh.timestamp; +/* + if (delta >> 31) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: clipping non-monotonical timestamp %uD->%uD", + lh.timestamp, ch.timestamp); + + delta = 0; + + ch.timestamp = lh.timestamp; + } +*/ + rpkt = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + + ngx_rtmp_prepare_message(s, &ch, &lh, rpkt); + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + + if (codec_ctx) { + + if (h->type == NGX_RTMP_MSG_AUDIO) { + header = codec_ctx->aac_header; + + if (lacf->interleave) { + coheader = codec_ctx->avc_header; + } + + if (codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC && + ngx_rtmp_is_codec_header(in)) + { + prio = 0; + mandatory = 1; + } + + } else { + header = codec_ctx->avc_header; + + if (lacf->interleave) { + coheader = codec_ctx->aac_header; + } + + if (codec_ctx->video_codec_id == NGX_RTMP_VIDEO_H264 && + ngx_rtmp_is_codec_header(in)) + { + prio = 0; + mandatory = 1; + } + } + + if (codec_ctx->meta) { + meta = codec_ctx->meta; + meta_version = codec_ctx->meta_version; + } + } + + /* broadcast to all subscribers */ + + for (pctx = ctx->stream->ctx; pctx; pctx = pctx->next) { + if (pctx == ctx || pctx->paused) { + continue; + } + + ss = pctx->session; + cs = &pctx->cs[csidx]; + + /* send metadata */ + + if (meta && meta_version != pctx->meta_version) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: meta"); + + if (ngx_rtmp_send_message(ss, meta, 0) == NGX_OK) { + pctx->meta_version = meta_version; + } + } + + /* sync stream */ + + if (cs->active && (lacf->sync && cs->dropped > lacf->sync)) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: sync %s dropped=%uD", type_s, cs->dropped); + + cs->active = 0; + cs->dropped = 0; + } + + /* absolute packet */ + + if (!cs->active) { + + if (mandatory) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: skipping header"); + continue; + } + + if (lacf->wait_video && h->type == NGX_RTMP_MSG_AUDIO && + !pctx->cs[0].active) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: waiting for video"); + continue; + } + + if (lacf->wait_key && prio != NGX_RTMP_VIDEO_KEY_FRAME && + (lacf->interleave || h->type == NGX_RTMP_MSG_VIDEO)) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: skip non-key"); + continue; + } + + dummy_audio = 0; + if (lacf->wait_video && h->type == NGX_RTMP_MSG_VIDEO && + !pctx->cs[1].active) + { + dummy_audio = 1; + if (aapkt == NULL) { + aapkt = ngx_rtmp_alloc_shared_buf(cscf); + ngx_rtmp_prepare_message(s, &clh, NULL, aapkt); + } + } + + if (header || coheader) { + + /* send absolute codec header */ + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: abs %s header timestamp=%uD", + type_s, lh.timestamp); + + if (header) { + if (apkt == NULL) { + apkt = ngx_rtmp_append_shared_bufs(cscf, NULL, header); + ngx_rtmp_prepare_message(s, &lh, NULL, apkt); + } + + rc = ngx_rtmp_send_message(ss, apkt, 0); + if (rc != NGX_OK) { + continue; + } + } + + if (coheader) { + if (acopkt == NULL) { + acopkt = ngx_rtmp_append_shared_bufs(cscf, NULL, coheader); + ngx_rtmp_prepare_message(s, &clh, NULL, acopkt); + } + + rc = ngx_rtmp_send_message(ss, acopkt, 0); + if (rc != NGX_OK) { + continue; + } + + } else if (dummy_audio) { + ngx_rtmp_send_message(ss, aapkt, 0); + } + + cs->timestamp = lh.timestamp; + cs->active = 1; + ss->current_time = cs->timestamp; + + } else { + + /* send absolute packet */ + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: abs %s packet timestamp=%uD", + type_s, ch.timestamp); + + if (apkt == NULL) { + apkt = ngx_rtmp_append_shared_bufs(cscf, NULL, in); + ngx_rtmp_prepare_message(s, &ch, NULL, apkt); + } + + rc = ngx_rtmp_send_message(ss, apkt, prio); + if (rc != NGX_OK) { + continue; + } + + cs->timestamp = ch.timestamp; + cs->active = 1; + ss->current_time = cs->timestamp; + + ++peers; + + if (dummy_audio) { + ngx_rtmp_send_message(ss, aapkt, 0); + } + + continue; + } + } + + /* send relative packet */ + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: rel %s packet delta=%uD", + type_s, delta); + + if (ngx_rtmp_send_message(ss, rpkt, prio) != NGX_OK) { + ++pctx->ndropped; + + cs->dropped += delta; + + if (mandatory) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, ss->connection->log, 0, + "live: mandatory packet failed"); + ngx_rtmp_finalize_session(ss); + } + + continue; + } + + cs->timestamp += delta; + ++peers; + ss->current_time = cs->timestamp; + } + + if (rpkt) { + ngx_rtmp_free_shared_chain(cscf, rpkt); + } + + if (apkt) { + ngx_rtmp_free_shared_chain(cscf, apkt); + } + + if (aapkt) { + ngx_rtmp_free_shared_chain(cscf, aapkt); + } + + if (acopkt) { + ngx_rtmp_free_shared_chain(cscf, acopkt); + } + + ngx_rtmp_update_bandwidth(&ctx->stream->bw_in, h->mlen); + ngx_rtmp_update_bandwidth(&ctx->stream->bw_out, h->mlen * peers); + + ngx_rtmp_update_bandwidth(h->type == NGX_RTMP_MSG_AUDIO ? + &ctx->stream->bw_in_audio : + &ctx->stream->bw_in_video, + h->mlen); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_live_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_live_ctx_t *ctx; + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + + if (lacf == NULL || !lacf->live) { + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: publish: name='%s' type='%s'", + v->name, v->type); + + /* join stream as publisher */ + + ngx_rtmp_live_join(s, v->name, 1); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (ctx == NULL || !ctx->publishing) { + goto next; + } + + ctx->silent = v->silent; + + if (!ctx->silent) { + ngx_rtmp_send_status(s, "NetStream.Publish.Start", + "status", "Start publishing"); + } + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_live_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_live_app_conf_t *lacf; + ngx_rtmp_live_ctx_t *ctx; + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_live_module); + + if (lacf == NULL || !lacf->live) { + goto next; + } + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "live: play: name='%s' start=%uD duration=%uD reset=%d", + v->name, (uint32_t) v->start, + (uint32_t) v->duration, (uint32_t) v->reset); + + /* join stream as subscriber */ + + ngx_rtmp_live_join(s, v->name, 0); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_live_module); + if (ctx == NULL) { + goto next; + } + + ctx->silent = v->silent; + + if (!ctx->silent && !lacf->play_restart) { + ngx_rtmp_send_status(s, "NetStream.Play.Start", + "status", "Start live"); + ngx_rtmp_send_sample_access(s); + } + +next: + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_live_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + /* register raw event handlers */ + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]); + *h = ngx_rtmp_live_av; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]); + *h = ngx_rtmp_live_av; + + /* chain handlers */ + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_live_publish; + + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_live_play; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_live_close_stream; + + next_pause = ngx_rtmp_pause; + ngx_rtmp_pause = ngx_rtmp_live_pause; + + next_stream_begin = ngx_rtmp_stream_begin; + ngx_rtmp_stream_begin = ngx_rtmp_live_stream_begin; + + next_stream_eof = ngx_rtmp_stream_eof; + ngx_rtmp_stream_eof = ngx_rtmp_live_stream_eof; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_live_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_live_module.h new file mode 100644 index 0000000..71eca36 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_live_module.h @@ -0,0 +1,83 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_LIVE_H_INCLUDED_ +#define _NGX_RTMP_LIVE_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_bandwidth.h" +#include "ngx_rtmp_streams.h" + + +typedef struct ngx_rtmp_live_ctx_s ngx_rtmp_live_ctx_t; +typedef struct ngx_rtmp_live_stream_s ngx_rtmp_live_stream_t; + + +typedef struct { + unsigned active:1; + uint32_t timestamp; + uint32_t csid; + uint32_t dropped; +} ngx_rtmp_live_chunk_stream_t; + + +struct ngx_rtmp_live_ctx_s { + ngx_rtmp_session_t *session; + ngx_rtmp_live_stream_t *stream; + ngx_rtmp_live_ctx_t *next; + ngx_uint_t ndropped; + ngx_rtmp_live_chunk_stream_t cs[2]; + ngx_uint_t meta_version; + ngx_event_t idle_evt; + unsigned active:1; + unsigned publishing:1; + unsigned silent:1; + unsigned paused:1; +}; + + +struct ngx_rtmp_live_stream_s { + u_char name[NGX_RTMP_MAX_NAME]; + ngx_rtmp_live_stream_t *next; + ngx_rtmp_live_ctx_t *ctx; + ngx_rtmp_bandwidth_t bw_in; + ngx_rtmp_bandwidth_t bw_in_audio; + ngx_rtmp_bandwidth_t bw_in_video; + ngx_rtmp_bandwidth_t bw_out; + ngx_msec_t epoch; + unsigned active:1; + unsigned publishing:1; +}; + + +typedef struct { + ngx_int_t nbuckets; + ngx_rtmp_live_stream_t **streams; + ngx_flag_t live; + ngx_flag_t meta; + ngx_msec_t sync; + ngx_msec_t idle_timeout; + ngx_flag_t atc; + ngx_flag_t interleave; + ngx_flag_t wait_key; + ngx_flag_t wait_video; + ngx_flag_t publish_notify; + ngx_flag_t play_restart; + ngx_flag_t idle_streams; + ngx_msec_t buflen; + ngx_pool_t *pool; + ngx_rtmp_live_stream_t *free_streams; +} ngx_rtmp_live_app_conf_t; + + +extern ngx_module_t ngx_rtmp_live_module; + + +#endif /* _NGX_RTMP_LIVE_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_log_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_log_module.c new file mode 100644 index 0000000..81016d0 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_log_module.c @@ -0,0 +1,1016 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_cmd_module.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_play_pt next_play; + + +static ngx_int_t ngx_rtmp_log_postconfiguration(ngx_conf_t *cf); +static void *ngx_rtmp_log_create_main_conf(ngx_conf_t *cf); +static void * ngx_rtmp_log_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_log_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static char * ngx_rtmp_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char * ngx_rtmp_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char * ngx_rtmp_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, + ngx_array_t *args, ngx_uint_t s); + + +typedef struct ngx_rtmp_log_op_s ngx_rtmp_log_op_t; + + +typedef size_t (*ngx_rtmp_log_op_getlen_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op); +typedef u_char * (*ngx_rtmp_log_op_getdata_pt)(ngx_rtmp_session_t *s, + u_char *buf, ngx_rtmp_log_op_t *log); + + +struct ngx_rtmp_log_op_s { + ngx_rtmp_log_op_getlen_pt getlen; + ngx_rtmp_log_op_getdata_pt getdata; + ngx_str_t value; + ngx_uint_t offset; +}; + + +typedef struct { + ngx_str_t name; + ngx_rtmp_log_op_getlen_pt getlen; + ngx_rtmp_log_op_getdata_pt getdata; + ngx_uint_t offset; +} ngx_rtmp_log_var_t; + + +typedef struct { + ngx_str_t name; + ngx_array_t *ops; /* ngx_rtmp_log_op_t */ +} ngx_rtmp_log_fmt_t; + + +typedef struct { + ngx_open_file_t *file; + time_t disk_full_time; + time_t error_log_time; + ngx_rtmp_log_fmt_t *format; +} ngx_rtmp_log_t; + + +typedef struct { + ngx_array_t *logs; /* ngx_rtmp_log_t */ + ngx_uint_t off; +} ngx_rtmp_log_app_conf_t; + + +typedef struct { + ngx_array_t formats; /* ngx_rtmp_log_fmt_t */ + ngx_uint_t combined_used; +} ngx_rtmp_log_main_conf_t; + + +typedef struct { + unsigned play:1; + unsigned publish:1; + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; +} ngx_rtmp_log_ctx_t; + + +static ngx_str_t ngx_rtmp_access_log = ngx_string(NGX_HTTP_LOG_PATH); + + +static ngx_command_t ngx_rtmp_log_commands[] = { + + { ngx_string("access_log"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE12, + ngx_rtmp_log_set_log, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("log_format"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_2MORE, + ngx_rtmp_log_set_format, + NGX_RTMP_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_log_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_log_postconfiguration, /* postconfiguration */ + ngx_rtmp_log_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_log_create_app_conf, /* create app configuration */ + ngx_rtmp_log_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_log_module = { + NGX_MODULE_V1, + &ngx_rtmp_log_module_ctx, /* module context */ + ngx_rtmp_log_commands, /* module directives */ + NGX_RTMP_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_str_t ngx_rtmp_combined_fmt = + ngx_string("$remote_addr [$time_local] $command " + "\"$app\" \"$name\" \"$args\" - " + "$bytes_received $bytes_sent " + "\"$pageurl\" \"$flashver\" ($session_readable_time)"); + + +static size_t +ngx_rtmp_log_var_default_getlen(ngx_rtmp_session_t *s, ngx_rtmp_log_op_t *op) +{ + return op->value.len; +} + + +static u_char * +ngx_rtmp_log_var_default_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + return ngx_cpymem(buf, op->value.data, op->value.len); +} + + +static size_t +ngx_rtmp_log_var_connection_getlen(ngx_rtmp_session_t *s, ngx_rtmp_log_op_t *op) +{ + return NGX_INT_T_LEN; +} + +static u_char * +ngx_rtmp_log_var_connection_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + return ngx_sprintf(buf, "%ui", (ngx_uint_t) s->connection->number); +} + + +static size_t +ngx_rtmp_log_var_remote_addr_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return s->connection->addr_text.len; +} + + +static u_char * +ngx_rtmp_log_var_remote_addr_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + return ngx_cpymem(buf, s->connection->addr_text.data, + s->connection->addr_text.len); +} + + +static size_t +ngx_rtmp_log_var_msec_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return NGX_TIME_T_LEN + 4; +} + + +static u_char * +ngx_rtmp_log_var_msec_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + ngx_time_t *tp; + + tp = ngx_timeofday(); + + return ngx_sprintf(buf, "%T.%03M", tp->sec, tp->msec); +} + + +static size_t +ngx_rtmp_log_var_session_string_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return ((ngx_str_t *) ((u_char *) s + op->offset))->len; +} + + +static u_char * +ngx_rtmp_log_var_session_string_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + ngx_str_t *str; + + str = (ngx_str_t *) ((u_char *) s + op->offset); + + return ngx_cpymem(buf, str->data, str->len); +} + + +static size_t +ngx_rtmp_log_var_command_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return sizeof("PLAY+PUBLISH") - 1; +} + + +static u_char * +ngx_rtmp_log_var_command_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + ngx_rtmp_log_ctx_t *ctx; + ngx_str_t *cmd; + ngx_uint_t n; + + static ngx_str_t commands[] = { + ngx_string("NONE"), + ngx_string("PLAY"), + ngx_string("PUBLISH"), + ngx_string("PLAY+PUBLISH") + }; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module); + + n = ctx ? (ctx->play + ctx->publish * 2) : 0; + + cmd = &commands[n]; + + return ngx_cpymem(buf, cmd->data, cmd->len); +} + + +static size_t +ngx_rtmp_log_var_context_cstring_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return ngx_max(NGX_RTMP_MAX_NAME, NGX_RTMP_MAX_ARGS); +} + + +static u_char * +ngx_rtmp_log_var_context_cstring_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + ngx_rtmp_log_ctx_t *ctx; + u_char *p; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module); + if (ctx == NULL) { + return buf; + } + + p = (u_char *) ctx + op->offset; + while (*p) { + *buf++ = *p++; + } + + return buf; +} + + +static size_t +ngx_rtmp_log_var_session_uint32_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return NGX_INT32_LEN; +} + + +static u_char * +ngx_rtmp_log_var_session_uint32_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + uint32_t *v; + + v = (uint32_t *) ((uint8_t *) s + op->offset); + + return ngx_sprintf(buf, "%uD", *v); +} + + +static size_t +ngx_rtmp_log_var_time_local_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return ngx_cached_http_log_time.len; +} + + +static u_char * +ngx_rtmp_log_var_time_local_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + return ngx_cpymem(buf, ngx_cached_http_log_time.data, + ngx_cached_http_log_time.len); +} + + +static size_t +ngx_rtmp_log_var_session_time_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return NGX_INT64_LEN; +} + + +static u_char * +ngx_rtmp_log_var_session_time_getdata(ngx_rtmp_session_t *s, u_char *buf, + ngx_rtmp_log_op_t *op) +{ + return ngx_sprintf(buf, "%L", + (int64_t) (ngx_current_msec - s->epoch) / 1000); +} + + +static size_t +ngx_rtmp_log_var_session_readable_time_getlen(ngx_rtmp_session_t *s, + ngx_rtmp_log_op_t *op) +{ + return NGX_INT_T_LEN + sizeof("d 23h 59m 59s") - 1; +} + + +static u_char * +ngx_rtmp_log_var_session_readable_time_getdata(ngx_rtmp_session_t *s, + u_char *buf, ngx_rtmp_log_op_t *op) +{ + int64_t v; + ngx_uint_t days, hours, minutes, seconds; + + v = (ngx_current_msec - s->epoch) / 1000; + + days = (ngx_uint_t) (v / (60 * 60 * 24)); + hours = (ngx_uint_t) (v / (60 * 60) % 24); + minutes = (ngx_uint_t) (v / 60 % 60); + seconds = (ngx_uint_t) (v % 60); + + if (days) { + buf = ngx_sprintf(buf, "%uid ", days); + } + + if (days || hours) { + buf = ngx_sprintf(buf, "%uih ", hours); + } + + if (days || hours || minutes) { + buf = ngx_sprintf(buf, "%uim ", minutes); + } + + buf = ngx_sprintf(buf, "%uis", seconds); + + return buf; +} + + +static ngx_rtmp_log_var_t ngx_rtmp_log_vars[] = { + { ngx_string("connection"), + ngx_rtmp_log_var_connection_getlen, + ngx_rtmp_log_var_connection_getdata, + 0 }, + + { ngx_string("remote_addr"), + ngx_rtmp_log_var_remote_addr_getlen, + ngx_rtmp_log_var_remote_addr_getdata, + 0 }, + + { ngx_string("app"), + ngx_rtmp_log_var_session_string_getlen, + ngx_rtmp_log_var_session_string_getdata, + offsetof(ngx_rtmp_session_t, app) }, + + { ngx_string("flashver"), + ngx_rtmp_log_var_session_string_getlen, + ngx_rtmp_log_var_session_string_getdata, + offsetof(ngx_rtmp_session_t, flashver) }, + + { ngx_string("swfurl"), + ngx_rtmp_log_var_session_string_getlen, + ngx_rtmp_log_var_session_string_getdata, + offsetof(ngx_rtmp_session_t, swf_url) }, + + { ngx_string("tcurl"), + ngx_rtmp_log_var_session_string_getlen, + ngx_rtmp_log_var_session_string_getdata, + offsetof(ngx_rtmp_session_t, tc_url) }, + + { ngx_string("pageurl"), + ngx_rtmp_log_var_session_string_getlen, + ngx_rtmp_log_var_session_string_getdata, + offsetof(ngx_rtmp_session_t, page_url) }, + + { ngx_string("command"), + ngx_rtmp_log_var_command_getlen, + ngx_rtmp_log_var_command_getdata, + 0 }, + + { ngx_string("name"), + ngx_rtmp_log_var_context_cstring_getlen, + ngx_rtmp_log_var_context_cstring_getdata, + offsetof(ngx_rtmp_log_ctx_t, name) }, + + { ngx_string("args"), + ngx_rtmp_log_var_context_cstring_getlen, + ngx_rtmp_log_var_context_cstring_getdata, + offsetof(ngx_rtmp_log_ctx_t, args) }, + + { ngx_string("bytes_sent"), + ngx_rtmp_log_var_session_uint32_getlen, + ngx_rtmp_log_var_session_uint32_getdata, + offsetof(ngx_rtmp_session_t, out_bytes) }, + + { ngx_string("bytes_received"), + ngx_rtmp_log_var_session_uint32_getlen, + ngx_rtmp_log_var_session_uint32_getdata, + offsetof(ngx_rtmp_session_t, in_bytes) }, + + { ngx_string("time_local"), + ngx_rtmp_log_var_time_local_getlen, + ngx_rtmp_log_var_time_local_getdata, + 0 }, + + { ngx_string("msec"), + ngx_rtmp_log_var_msec_getlen, + ngx_rtmp_log_var_msec_getdata, + 0 }, + + { ngx_string("session_time"), + ngx_rtmp_log_var_session_time_getlen, + ngx_rtmp_log_var_session_time_getdata, + 0 }, + + { ngx_string("session_readable_time"), + ngx_rtmp_log_var_session_readable_time_getlen, + ngx_rtmp_log_var_session_readable_time_getdata, + 0 }, + + { ngx_null_string, NULL, NULL, 0 } +}; + + +static void * +ngx_rtmp_log_create_main_conf(ngx_conf_t *cf) +{ + ngx_rtmp_log_main_conf_t *lmcf; + ngx_rtmp_log_fmt_t *fmt; + + lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_log_main_conf_t)); + if (lmcf == NULL) { + return NULL; + } + + if (ngx_array_init(&lmcf->formats, cf->pool, 4, sizeof(ngx_rtmp_log_fmt_t)) + != NGX_OK) + { + return NULL; + } + + fmt = ngx_array_push(&lmcf->formats); + if (fmt == NULL) { + return NULL; + } + + ngx_str_set(&fmt->name, "combined"); + + fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_rtmp_log_op_t)); + if (fmt->ops == NULL) { + return NULL; + } + + return lmcf; + +} + + +static void * +ngx_rtmp_log_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_log_app_conf_t *lacf; + + lacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_log_app_conf_t)); + if (lacf == NULL) { + return NULL; + } + + return lacf; +} + + +static char * +ngx_rtmp_log_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_log_app_conf_t *prev = parent; + ngx_rtmp_log_app_conf_t *conf = child; + ngx_rtmp_log_main_conf_t *lmcf; + ngx_rtmp_log_fmt_t *fmt; + ngx_rtmp_log_t *log; + + if (conf->logs || conf->off) { + return NGX_OK; + } + + conf->logs = prev->logs; + conf->off = prev->off; + + if (conf->logs || conf->off) { + return NGX_OK; + } + + conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_rtmp_log_t)); + if (conf->logs == NULL) { + return NGX_CONF_ERROR; + } + + log = ngx_array_push(conf->logs); + if (log == NULL) { + return NGX_CONF_ERROR; + } + + log->file = ngx_conf_open_file(cf->cycle, &ngx_rtmp_access_log); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + log->disk_full_time = 0; + log->error_log_time = 0; + + lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module); + fmt = lmcf->formats.elts; + + log->format = &fmt[0]; + lmcf->combined_used = 1; + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_log_app_conf_t *lacf = conf; + + ngx_rtmp_log_main_conf_t *lmcf; + ngx_rtmp_log_fmt_t *fmt; + ngx_rtmp_log_t *log; + ngx_str_t *value, name; + ngx_uint_t n; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + lacf->off = 1; + return NGX_CONF_OK; + } + + if (lacf->logs == NULL) { + lacf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_rtmp_log_t)); + if (lacf->logs == NULL) { + return NGX_CONF_ERROR; + } + } + + log = ngx_array_push(lacf->logs); + if (log == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(log, sizeof(*log)); + + lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module); + + log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2) { + ngx_str_set(&name, "combined"); + lmcf->combined_used = 1; + + } else { + name = value[2]; + if (ngx_strcmp(name.data, "combined") == 0) { + lmcf->combined_used = 1; + } + } + + fmt = lmcf->formats.elts; + for (n = 0; n < lmcf->formats.nelts; ++n, ++fmt) { + if (fmt->name.len == name.len && + ngx_strncasecmp(fmt->name.data, name.data, name.len) == 0) + { + log->format = fmt; + break; + } + } + + if (log->format == NULL) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "unknown log format \"%V\"", + &name); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_log_main_conf_t *lmcf = conf; + ngx_rtmp_log_fmt_t *fmt; + ngx_str_t *value; + ngx_uint_t i; + + value = cf->args->elts; + + if (cf->cmd_type != NGX_RTMP_MAIN_CONF) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"log_format\" directive can only be used on " + "\"rtmp\" level"); + } + + fmt = lmcf->formats.elts; + for (i = 0; i < lmcf->formats.nelts; i++) { + if (fmt[i].name.len == value[1].len && + ngx_strcmp(fmt[i].name.data, value[1].data) == 0) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"log_format\" name \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + } + + fmt = ngx_array_push(&lmcf->formats); + if (fmt == NULL) { + return NGX_CONF_ERROR; + } + + fmt->name = value[1]; + + fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_rtmp_log_op_t)); + if (fmt->ops == NULL) { + return NGX_CONF_ERROR; + } + + return ngx_rtmp_log_compile_format(cf, fmt->ops, cf->args, 2); +} + + +static char * +ngx_rtmp_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, ngx_array_t *args, + ngx_uint_t s) +{ + size_t i, len; + u_char *data, *d, c; + ngx_uint_t bracket; + ngx_str_t *value, var; + ngx_rtmp_log_op_t *op; + ngx_rtmp_log_var_t *v; + + value = args->elts; + + for (; s < args->nelts; ++s) { + i = 0; + + len = value[s].len; + d = value[s].data; + + while (i < len) { + + op = ngx_array_push(ops); + if (op == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(op, sizeof(*op)); + + data = &d[i]; + + if (d[i] == '$') { + if (++i == len) { + goto invalid; + } + + if (d[i] == '{') { + bracket = 1; + if (++i == len) { + goto invalid; + } + } else { + bracket = 0; + } + + var.data = &d[i]; + + for (var.len = 0; i < len; ++i, ++var.len) { + c = d[i]; + + if (c == '}' && bracket) { + ++i; + bracket = 0; + break; + } + + if ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + (c == '_')) + { + continue; + } + + break; + } + + if (bracket) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "missing closing bracket in \"%V\"", + &var); + return NGX_CONF_ERROR; + } + + if (var.len == 0) { + goto invalid; + } + + for (v = ngx_rtmp_log_vars; v->name.len; ++v) { + if (v->name.len == var.len && + ngx_strncmp(v->name.data, var.data, var.len) == 0) + { + op->getlen = v->getlen; + op->getdata = v->getdata; + op->offset = v->offset; + break; + } + } + + if (v->name.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown variable \"%V\"", &var); + return NGX_CONF_ERROR; + } + + continue; + } + + ++i; + + while (i < len && d[i] != '$') { + ++i; + } + + op->getlen = ngx_rtmp_log_var_default_getlen; + op->getdata = ngx_rtmp_log_var_default_getdata; + + op->value.len = &d[i] - data; + + op->value.data = ngx_pnalloc(cf->pool, op->value.len); + if (op->value.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(op->value.data, data, op->value.len); + } + } + + return NGX_CONF_OK; + +invalid: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%s\"", data); + + return NGX_CONF_ERROR; +} + + +static ngx_rtmp_log_ctx_t * +ngx_rtmp_log_set_names(ngx_rtmp_session_t *s, u_char *name, u_char *args) +{ + ngx_rtmp_log_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_log_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_log_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_log_module); + } + + ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME); + ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS); + + return ctx; +} + + +static ngx_int_t +ngx_rtmp_log_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_log_ctx_t *ctx; + + if (s->auto_pushed || s->relay) { + goto next; + } + + ctx = ngx_rtmp_log_set_names(s, v->name, v->args); + if (ctx == NULL) { + goto next; + } + + ctx->publish = 1; + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_log_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_log_ctx_t *ctx; + + if (s->auto_pushed || s->relay) { + goto next; + } + + ctx = ngx_rtmp_log_set_names(s, v->name, v->args); + if (ctx == NULL) { + goto next; + } + + ctx->play = 1; + +next: + return next_play(s, v); +} + + +static void +ngx_rtmp_log_write(ngx_rtmp_session_t *s, ngx_rtmp_log_t *log, u_char *buf, + size_t len) +{ + u_char *name; + time_t now; + ssize_t n; + int err; + + err = 0; + name = log->file->name.data; + n = ngx_write_fd(log->file->fd, buf, len); + + if (n == (ssize_t) len) { + return; + } + + now = ngx_time(); + + if (n == -1) { + err = ngx_errno; + + if (err == NGX_ENOSPC) { + log->disk_full_time = now; + } + + if (now - log->error_log_time > 59) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, err, + ngx_write_fd_n " to \"%s\" failed", name); + log->error_log_time = now; + } + } + + if (now - log->error_log_time > 59) { + ngx_log_error(NGX_LOG_ALERT, s->connection->log, err, + ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", + name, n, len); + log->error_log_time = now; + } +} + + +static ngx_int_t +ngx_rtmp_log_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_log_app_conf_t *lacf; + ngx_rtmp_log_t *log; + ngx_rtmp_log_op_t *op; + ngx_uint_t n, i; + u_char *line, *p; + size_t len; + + if (s->auto_pushed || s->relay) { + return NGX_OK; + } + + lacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_log_module); + if (lacf == NULL || lacf->off || lacf->logs == NULL) { + return NGX_OK; + } + + log = lacf->logs->elts; + for (i = 0; i < lacf->logs->nelts; ++i, ++log) { + + if (ngx_time() == log->disk_full_time) { + /* FreeBSD full disk protection; + * nginx http logger does the same */ + continue; + } + + len = 0; + op = log->format->ops->elts; + for (n = 0; n < log->format->ops->nelts; ++n, ++op) { + len += op->getlen(s, op); + } + + len += NGX_LINEFEED_SIZE; + + line = ngx_palloc(s->connection->pool, len); + if (line == NULL) { + return NGX_OK; + } + + p = line; + op = log->format->ops->elts; + for (n = 0; n < log->format->ops->nelts; ++n, ++op) { + p = op->getdata(s, p, op); + } + + ngx_linefeed(p); + + ngx_rtmp_log_write(s, log, line, p - line); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_log_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + ngx_rtmp_log_main_conf_t *lmcf; + ngx_array_t a; + ngx_rtmp_log_fmt_t *fmt; + ngx_str_t *value; + + lmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_log_module); + if (lmcf->combined_used) { + if (ngx_array_init(&a, cf->pool, 1, sizeof(ngx_str_t)) != NGX_OK) { + return NGX_ERROR; + } + + value = ngx_array_push(&a); + if (value == NULL) { + return NGX_ERROR; + } + + *value = ngx_rtmp_combined_fmt; + fmt = lmcf->formats.elts; + + if (ngx_rtmp_log_compile_format(cf, fmt->ops, &a, 0) + != NGX_CONF_OK) + { + return NGX_ERROR; + } + } + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); + *h = ngx_rtmp_log_disconnect; + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_log_publish; + + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_log_play; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c new file mode 100644 index 0000000..0259ca2 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c @@ -0,0 +1,2591 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_play_module.h" +#include "ngx_rtmp_codec_module.h" +#include "ngx_rtmp_streams.h" + + +static ngx_int_t ngx_rtmp_mp4_postconfiguration(ngx_conf_t *cf); +static ngx_int_t ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_int_t aindex, ngx_int_t vindex); +static ngx_int_t ngx_rtmp_mp4_done(ngx_rtmp_session_t *s, ngx_file_t *f); +static ngx_int_t ngx_rtmp_mp4_start(ngx_rtmp_session_t *s, ngx_file_t *f); +static ngx_int_t ngx_rtmp_mp4_seek(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_uint_t offset); +static ngx_int_t ngx_rtmp_mp4_stop(ngx_rtmp_session_t *s, ngx_file_t *f); +static ngx_int_t ngx_rtmp_mp4_send(ngx_rtmp_session_t *s, ngx_file_t *f, + ngx_uint_t *ts); +static ngx_int_t ngx_rtmp_mp4_reset(ngx_rtmp_session_t *s); + + +#define NGX_RTMP_MP4_MAX_FRAMES 8 + + +#pragma pack(push,4) + + +/* disable zero-sized array warning by msvc */ + +#if (NGX_WIN32) +#pragma warning(push) +#pragma warning(disable:4200) +#endif + + +typedef struct { + uint32_t first_chunk; + uint32_t samples_per_chunk; + uint32_t sample_descrption_index; +} ngx_rtmp_mp4_chunk_entry_t; + + +typedef struct { + uint32_t version_flags; + uint32_t entry_count; + ngx_rtmp_mp4_chunk_entry_t entries[0]; +} ngx_rtmp_mp4_chunks_t; + + +typedef struct { + uint32_t sample_count; + uint32_t sample_delta; +} ngx_rtmp_mp4_time_entry_t; + + +typedef struct { + uint32_t version_flags; + uint32_t entry_count; + ngx_rtmp_mp4_time_entry_t entries[0]; +} ngx_rtmp_mp4_times_t; + + +typedef struct { + uint32_t sample_count; + uint32_t sample_offset; +} ngx_rtmp_mp4_delay_entry_t; + + +typedef struct { + uint32_t version_flags; + uint32_t entry_count; + ngx_rtmp_mp4_delay_entry_t entries[0]; +} ngx_rtmp_mp4_delays_t; + + +typedef struct { + uint32_t version_flags; + uint32_t entry_count; + uint32_t entries[0]; +} ngx_rtmp_mp4_keys_t; + + +typedef struct { + uint32_t version_flags; + uint32_t sample_size; + uint32_t sample_count; + uint32_t entries[0]; +} ngx_rtmp_mp4_sizes_t; + + +typedef struct { + uint32_t version_flags; + uint32_t field_size; + uint32_t sample_count; + uint32_t entries[0]; +} ngx_rtmp_mp4_sizes2_t; + + +typedef struct { + uint32_t version_flags; + uint32_t entry_count; + uint32_t entries[0]; +} ngx_rtmp_mp4_offsets_t; + + +typedef struct { + uint32_t version_flags; + uint32_t entry_count; + uint64_t entries[0]; +} ngx_rtmp_mp4_offsets64_t; + + +#if (NGX_WIN32) +#pragma warning(pop) +#endif + + +#pragma pack(pop) + + +typedef struct { + uint32_t timestamp; + uint32_t last_timestamp; + off_t offset; + size_t size; + ngx_int_t key; + uint32_t delay; + + unsigned not_first:1; + unsigned valid:1; + + ngx_uint_t pos; + + ngx_uint_t key_pos; + + ngx_uint_t chunk; + ngx_uint_t chunk_pos; + ngx_uint_t chunk_count; + + ngx_uint_t time_pos; + ngx_uint_t time_count; + + ngx_uint_t delay_pos; + ngx_uint_t delay_count; + + ngx_uint_t size_pos; +} ngx_rtmp_mp4_cursor_t; + + +typedef struct { + ngx_uint_t id; + + ngx_int_t type; + ngx_int_t codec; + uint32_t csid; + u_char fhdr; + ngx_int_t time_scale; + uint64_t duration; + + u_char *header; + size_t header_size; + unsigned header_sent:1; + + ngx_rtmp_mp4_times_t *times; + ngx_rtmp_mp4_delays_t *delays; + ngx_rtmp_mp4_keys_t *keys; + ngx_rtmp_mp4_chunks_t *chunks; + ngx_rtmp_mp4_sizes_t *sizes; + ngx_rtmp_mp4_sizes2_t *sizes2; + ngx_rtmp_mp4_offsets_t *offsets; + ngx_rtmp_mp4_offsets64_t *offsets64; + ngx_rtmp_mp4_cursor_t cursor; +} ngx_rtmp_mp4_track_t; + + +typedef struct { + void *mmaped; + size_t mmaped_size; + ngx_fd_t extra; + + unsigned meta_sent:1; + + ngx_rtmp_mp4_track_t tracks[2]; + ngx_rtmp_mp4_track_t *track; + ngx_uint_t ntracks; + + ngx_uint_t width; + ngx_uint_t height; + ngx_uint_t nchannels; + ngx_uint_t sample_size; + ngx_uint_t sample_rate; + + ngx_int_t atracks, vtracks; + ngx_int_t aindex, vindex; + + uint32_t start_timestamp, epoch; +} ngx_rtmp_mp4_ctx_t; + + +#define ngx_rtmp_mp4_make_tag(a, b, c, d) \ + ((uint32_t)d << 24 | (uint32_t)c << 16 | (uint32_t)b << 8 | (uint32_t)a) + + +static ngx_inline uint32_t +ngx_rtmp_mp4_to_rtmp_timestamp(ngx_rtmp_mp4_track_t *t, uint64_t ts) +{ + return (uint32_t) (ts * 1000 / t->time_scale); +} + + +static ngx_inline uint32_t +ngx_rtmp_mp4_from_rtmp_timestamp(ngx_rtmp_mp4_track_t *t, uint32_t ts) +{ + return (uint64_t) ts * t->time_scale / 1000; +} + + +#define NGX_RTMP_MP4_BUFLEN_ADDON 1000 + + +static u_char ngx_rtmp_mp4_buffer[1024*1024]; + + +#if (NGX_WIN32) +static void * +ngx_rtmp_mp4_mmap(ngx_fd_t fd, size_t size, off_t offset, ngx_fd_t *extra) +{ + void *data; + + *extra = CreateFileMapping(fd, NULL, PAGE_READONLY, + (DWORD) ((uint64_t) size >> 32), + (DWORD) (size & 0xffffffff), + NULL); + if (*extra == NULL) { + return NULL; + } + + data = MapViewOfFile(*extra, FILE_MAP_READ, + (DWORD) ((uint64_t) offset >> 32), + (DWORD) (offset & 0xffffffff), + size); + + if (data == NULL) { + CloseHandle(*extra); + } + + /* + * non-NULL result means map view handle is open + * and should be closed later + */ + + return data; +} + + +static ngx_int_t +ngx_rtmp_mp4_munmap(void *data, size_t size, ngx_fd_t *extra) +{ + ngx_int_t rc; + + rc = NGX_OK; + + if (UnmapViewOfFile(data) == 0) { + rc = NGX_ERROR; + } + + if (CloseHandle(*extra) == 0) { + rc = NGX_ERROR; + } + + return rc; +} + +#else + +static void * +ngx_rtmp_mp4_mmap(ngx_fd_t fd, size_t size, off_t offset, ngx_fd_t *extra) +{ + void *data; + + data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset); + + /* valid address is never NULL since there's no MAP_FIXED */ + + return data == MAP_FAILED ? NULL : data; +} + + +static ngx_int_t +ngx_rtmp_mp4_munmap(void *data, size_t size, ngx_fd_t *extra) +{ + return munmap(data, size); +} + +#endif + + +static ngx_int_t ngx_rtmp_mp4_parse(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_trak(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_mdhd(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_hdlr(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stsd(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stsc(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stts(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_ctts(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stss(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stsz(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stz2(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_stco(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_co64(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_avc1(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_avcC(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_mp4a(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_mp4v(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_esds(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_mp3(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_nmos(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_spex(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); + + +typedef ngx_int_t (*ngx_rtmp_mp4_box_pt)(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); + +typedef struct { + uint32_t tag; + ngx_rtmp_mp4_box_pt handler; +} ngx_rtmp_mp4_box_t; + + +static ngx_rtmp_mp4_box_t ngx_rtmp_mp4_boxes[] = { + { ngx_rtmp_mp4_make_tag('t','r','a','k'), ngx_rtmp_mp4_parse_trak }, + { ngx_rtmp_mp4_make_tag('m','d','i','a'), ngx_rtmp_mp4_parse }, + { ngx_rtmp_mp4_make_tag('m','d','h','d'), ngx_rtmp_mp4_parse_mdhd }, + { ngx_rtmp_mp4_make_tag('h','d','l','r'), ngx_rtmp_mp4_parse_hdlr }, + { ngx_rtmp_mp4_make_tag('m','i','n','f'), ngx_rtmp_mp4_parse }, + { ngx_rtmp_mp4_make_tag('s','t','b','l'), ngx_rtmp_mp4_parse }, + { ngx_rtmp_mp4_make_tag('s','t','s','d'), ngx_rtmp_mp4_parse_stsd }, + { ngx_rtmp_mp4_make_tag('s','t','s','c'), ngx_rtmp_mp4_parse_stsc }, + { ngx_rtmp_mp4_make_tag('s','t','t','s'), ngx_rtmp_mp4_parse_stts }, + { ngx_rtmp_mp4_make_tag('c','t','t','s'), ngx_rtmp_mp4_parse_ctts }, + { ngx_rtmp_mp4_make_tag('s','t','s','s'), ngx_rtmp_mp4_parse_stss }, + { ngx_rtmp_mp4_make_tag('s','t','s','z'), ngx_rtmp_mp4_parse_stsz }, + { ngx_rtmp_mp4_make_tag('s','t','z','2'), ngx_rtmp_mp4_parse_stz2 }, + { ngx_rtmp_mp4_make_tag('s','t','c','o'), ngx_rtmp_mp4_parse_stco }, + { ngx_rtmp_mp4_make_tag('c','o','6','4'), ngx_rtmp_mp4_parse_co64 }, + { ngx_rtmp_mp4_make_tag('a','v','c','1'), ngx_rtmp_mp4_parse_avc1 }, + { ngx_rtmp_mp4_make_tag('a','v','c','C'), ngx_rtmp_mp4_parse_avcC }, + { ngx_rtmp_mp4_make_tag('m','p','4','a'), ngx_rtmp_mp4_parse_mp4a }, + { ngx_rtmp_mp4_make_tag('m','p','4','v'), ngx_rtmp_mp4_parse_mp4v }, + { ngx_rtmp_mp4_make_tag('e','s','d','s'), ngx_rtmp_mp4_parse_esds }, + { ngx_rtmp_mp4_make_tag('.','m','p','3'), ngx_rtmp_mp4_parse_mp3 }, + { ngx_rtmp_mp4_make_tag('n','m','o','s'), ngx_rtmp_mp4_parse_nmos }, + { ngx_rtmp_mp4_make_tag('s','p','e','x'), ngx_rtmp_mp4_parse_spex }, + { ngx_rtmp_mp4_make_tag('w','a','v','e'), ngx_rtmp_mp4_parse } +}; + + +static ngx_int_t ngx_rtmp_mp4_parse_descr(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_es(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_dc(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); +static ngx_int_t ngx_rtmp_mp4_parse_ds(ngx_rtmp_session_t *s, u_char *pos, + u_char *last); + + +typedef ngx_int_t (*ngx_rtmp_mp4_descriptor_pt)(ngx_rtmp_session_t *s, + u_char *pos, u_char *last); + +typedef struct { + uint8_t tag; + ngx_rtmp_mp4_descriptor_pt handler; +} ngx_rtmp_mp4_descriptor_t; + + +static ngx_rtmp_mp4_descriptor_t ngx_rtmp_mp4_descriptors[] = { + { 0x03, ngx_rtmp_mp4_parse_es }, /* MPEG ES Descriptor */ + { 0x04, ngx_rtmp_mp4_parse_dc }, /* MPEG DecoderConfig Descriptor */ + { 0x05, ngx_rtmp_mp4_parse_ds } /* MPEG DecoderSpec Descriptor */ +}; + + +static ngx_rtmp_module_t ngx_rtmp_mp4_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_mp4_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_mp4_module = { + NGX_MODULE_V1, + &ngx_rtmp_mp4_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_RTMP_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_rtmp_mp4_parse_trak(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track) { + return NGX_OK; + } + + ctx->track = (ctx->ntracks == sizeof(ctx->tracks) / sizeof(ctx->tracks[0])) + ? NULL : &ctx->tracks[ctx->ntracks]; + + if (ctx->track) { + ngx_memzero(ctx->track, sizeof(*ctx->track)); + ctx->track->id = ctx->ntracks; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: trying track %ui", ctx->ntracks); + } + + if (ngx_rtmp_mp4_parse(s, pos, last) != NGX_OK) { + return NGX_ERROR; + } + + if (ctx->track && ctx->track->type && + (ctx->ntracks == 0 || + ctx->tracks[0].type != ctx->tracks[ctx->ntracks].type)) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: adding track %ui", ctx->ntracks); + + if (ctx->track->type == NGX_RTMP_MSG_AUDIO) { + if (ctx->atracks++ != ctx->aindex) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: skipping audio track %ui!=%ui", + ctx->atracks - 1, ctx->aindex); + ctx->track = NULL; + return NGX_OK; + } + + } else { + if (ctx->vtracks++ != ctx->vindex) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: skipping video track %i!=%i", + ctx->vtracks - 1, ctx->vindex); + ctx->track = NULL; + return NGX_OK; + } + } + + ++ctx->ntracks; + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: ignoring track %ui", ctx->ntracks); + } + + ctx->track = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_mdhd(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + uint8_t version; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track == NULL) { + return NGX_OK; + } + + t = ctx->track; + + if (pos + 1 > last) { + return NGX_ERROR; + } + + version = *(uint8_t *) pos; + + switch (version) { + case 0: + if (pos + 20 > last) { + return NGX_ERROR; + } + + pos += 12; + t->time_scale = ngx_rtmp_r32(*(uint32_t *) pos); + pos += 4; + t->duration = ngx_rtmp_r32(*(uint32_t *) pos); + break; + + case 1: + if (pos + 28 > last) { + return NGX_ERROR; + } + + pos += 20; + t->time_scale = ngx_rtmp_r32(*(uint32_t *) pos); + pos += 4; + t->duration = ngx_rtmp_r64(*(uint64_t *) pos); + break; + + default: + return NGX_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: duration time_scale=%ui duration=%uL", + t->time_scale, t->duration); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_hdlr(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + uint32_t type; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track == NULL) { + return NGX_OK; + } + + if (pos + 12 > last) { + return NGX_ERROR; + } + + type = *(uint32_t *)(pos + 8); + + if (type == ngx_rtmp_mp4_make_tag('v','i','d','e')) { + ctx->track->type = NGX_RTMP_MSG_VIDEO; + ctx->track->csid = NGX_RTMP_CSID_VIDEO; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: video track"); + + } else if (type == ngx_rtmp_mp4_make_tag('s','o','u','n')) { + ctx->track->type = NGX_RTMP_MSG_AUDIO; + ctx->track->csid = NGX_RTMP_CSID_AUDIO; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: audio track"); + } else { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: unknown track"); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_video(ngx_rtmp_session_t *s, u_char *pos, u_char *last, + ngx_int_t codec) +{ + ngx_rtmp_mp4_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track == NULL) { + return NGX_OK; + } + + ctx->track->codec = codec; + + if (pos + 78 > last) { + return NGX_ERROR; + } + + pos += 24; + + ctx->width = ngx_rtmp_r16(*(uint16_t *) pos); + + pos += 2; + + ctx->height = ngx_rtmp_r16(*(uint16_t *) pos); + + pos += 52; + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: video settings codec=%i, width=%ui, height=%ui", + codec, ctx->width, ctx->height); + + if (ngx_rtmp_mp4_parse(s, pos, last) != NGX_OK) { + return NGX_ERROR; + } + + ctx->track->fhdr = (u_char) ctx->track->codec; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_audio(ngx_rtmp_session_t *s, u_char *pos, u_char *last, + ngx_int_t codec) +{ + ngx_rtmp_mp4_ctx_t *ctx; + u_char *p; + ngx_uint_t version; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track == NULL) { + return NGX_OK; + } + + ctx->track->codec = codec; + + if (pos + 28 > last) { + return NGX_ERROR; + } + + pos += 8; + + version = ngx_rtmp_r16(*(uint16_t *) pos); + + pos += 8; + + ctx->nchannels = ngx_rtmp_r16(*(uint16_t *) pos); + + pos += 2; + + ctx->sample_size = ngx_rtmp_r16(*(uint16_t *) pos); + + pos += 6; + + ctx->sample_rate = ngx_rtmp_r16(*(uint16_t *) pos); + + pos += 4; + + p = &ctx->track->fhdr; + + *p = 0; + + if (ctx->nchannels == 2) { + *p |= 0x01; + } + + if (ctx->sample_size == 16) { + *p |= 0x02; + } + + switch (ctx->sample_rate) { + case 5512: + break; + + case 11025: + *p |= 0x04; + break; + + case 22050: + *p |= 0x08; + break; + + default: /*44100 etc */ + *p |= 0x0c; + break; + } + + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: audio settings version=%ui, codec=%i, nchannels==%ui, " + "sample_size=%ui, sample_rate=%ui", + version, codec, ctx->nchannels, ctx->sample_size, + ctx->sample_rate); + + switch (version) { + case 1: + pos += 16; + break; + + case 2: + pos += 36; + } + + if (pos > last) { + return NGX_ERROR; + } + + if (ngx_rtmp_mp4_parse(s, pos, last) != NGX_OK) { + return NGX_ERROR; + } + + *p |= (ctx->track->codec << 4); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_avc1(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + return ngx_rtmp_mp4_parse_video(s, pos, last, NGX_RTMP_VIDEO_H264); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_mp4v(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + return ngx_rtmp_mp4_parse_video(s, pos, last, NGX_RTMP_VIDEO_H264); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_avcC(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + + if (pos == last) { + return NGX_OK; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track == NULL || ctx->track->codec != NGX_RTMP_VIDEO_H264) { + return NGX_OK; + } + + ctx->track->header = pos; + ctx->track->header_size = (size_t) (last - pos); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: video h264 header size=%uz", + ctx->track->header_size); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_mp4a(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + return ngx_rtmp_mp4_parse_audio(s, pos, last, NGX_RTMP_AUDIO_MP3); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_ds(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->header = pos; + t->header_size = (size_t) (last - pos); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: decoder header size=%uz", t->header_size); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_dc(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + uint8_t id; + ngx_rtmp_mp4_ctx_t *ctx; + ngx_int_t *pc; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx->track == NULL) { + return NGX_OK; + } + + if (pos + 13 > last) { + return NGX_ERROR; + } + + id = * (uint8_t *) pos; + pos += 13; + pc = &ctx->track->codec; + + switch (id) { + case 0x21: + *pc = NGX_RTMP_VIDEO_H264; + break; + + case 0x40: + case 0x66: + case 0x67: + case 0x68: + *pc = NGX_RTMP_AUDIO_AAC; + break; + + case 0x69: + case 0x6b: + *pc = NGX_RTMP_AUDIO_MP3; + break; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: decoder descriptor id=%i codec=%i", + (ngx_int_t) id, *pc); + + return ngx_rtmp_mp4_parse_descr(s, pos, last); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_es(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + uint16_t id; + uint8_t flags; + + if (pos + 3 > last) { + return NGX_ERROR; + } + + id = ngx_rtmp_r16(*(uint16_t *) pos); + pos += 2; + + flags = *(uint8_t *) pos; + ++pos; + + if (flags & 0x80) { /* streamDependenceFlag */ + pos += 2; + } + + if (flags & 0x40) { /* URL_FLag */ + return NGX_OK; + } + + if (flags & 0x20) { /* OCRstreamFlag */ + pos += 2; + } + + if (pos > last) { + return NGX_ERROR; + } + + (void) id; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: es descriptor es id=%i flags=%i", + (ngx_int_t) id, (ngx_int_t) flags); + + return ngx_rtmp_mp4_parse_descr(s, pos, last); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_descr(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + uint8_t tag, v; + uint32_t size; + ngx_uint_t n, ndesc; + ngx_rtmp_mp4_descriptor_t *ds; + + ndesc = sizeof(ngx_rtmp_mp4_descriptors) + / sizeof(ngx_rtmp_mp4_descriptors[0]); + + while (pos < last) { + tag = *(uint8_t *) pos++; + + for (size = 0, n = 0; n < 4; ++n) { + if (pos == last) { + return NGX_ERROR; + } + + v = *(uint8_t *) pos++; + + size = (size << 7) | (v & 0x7f); + + if (!(v & 0x80)) { + break; + } + } + + if (pos + size > last) { + return NGX_ERROR; + } + + ds = ngx_rtmp_mp4_descriptors;; + + for (n = 0; n < ndesc; ++n, ++ds) { + if (tag == ds->tag) { + break; + } + } + + if (n == ndesc) { + ds = NULL; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: descriptor%s tag=%i size=%uD", + ds ? "" : " unhandled", (ngx_int_t) tag, size); + + if (ds && ds->handler(s, pos, pos + size) != NGX_OK) { + return NGX_ERROR; + } + + pos += size; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_esds(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + if (pos + 4 > last) { + return NGX_ERROR; + } + + pos += 4; /* version */ + + return ngx_rtmp_mp4_parse_descr(s, pos, last); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_mp3(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + return ngx_rtmp_mp4_parse_audio(s, pos, last, NGX_RTMP_AUDIO_MP3); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_nmos(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + return ngx_rtmp_mp4_parse_audio(s, pos, last, NGX_RTMP_AUDIO_NELLY); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_spex(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + return ngx_rtmp_mp4_parse_audio(s, pos, last, NGX_RTMP_AUDIO_SPEEX); +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stsd(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + if (pos + 8 > last) { + return NGX_ERROR; + } + + pos += 8; + + ngx_rtmp_mp4_parse(s, pos, last); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stsc(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->chunks = (ngx_rtmp_mp4_chunks_t *) pos; + + if (pos + sizeof(*t->chunks) + ngx_rtmp_r32(t->chunks->entry_count) * + sizeof(t->chunks->entries[0]) + <= last) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: chunks entries=%uD", + ngx_rtmp_r32(t->chunks->entry_count)); + return NGX_OK; + } + + t->chunks = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stts(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->times = (ngx_rtmp_mp4_times_t *) pos; + + if (pos + sizeof(*t->times) + ngx_rtmp_r32(t->times->entry_count) * + sizeof(t->times->entries[0]) + <= last) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: times entries=%uD", + ngx_rtmp_r32(t->times->entry_count)); + return NGX_OK; + } + + t->times = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_ctts(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->delays = (ngx_rtmp_mp4_delays_t *) pos; + + if (pos + sizeof(*t->delays) + ngx_rtmp_r32(t->delays->entry_count) * + sizeof(t->delays->entries[0]) + <= last) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: delays entries=%uD", + ngx_rtmp_r32(t->delays->entry_count)); + return NGX_OK; + } + + t->delays = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stss(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->keys = (ngx_rtmp_mp4_keys_t *) pos; + + if (pos + sizeof(*t->keys) + ngx_rtmp_r32(t->keys->entry_count) * + sizeof(t->keys->entries[0]) + <= last) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: keys entries=%uD", + ngx_rtmp_r32(t->keys->entry_count)); + return NGX_OK; + } + + t->keys = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stsz(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->sizes = (ngx_rtmp_mp4_sizes_t *) pos; + + if (pos + sizeof(*t->sizes) <= last && t->sizes->sample_size) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: sizes size=%uD", + ngx_rtmp_r32(t->sizes->sample_size)); + return NGX_OK; + } + + if (pos + sizeof(*t->sizes) + ngx_rtmp_r32(t->sizes->sample_count) * + sizeof(t->sizes->entries[0]) + <= last) + + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: sizes entries=%uD", + ngx_rtmp_r32(t->sizes->sample_count)); + return NGX_OK; + } + + t->sizes = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stz2(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->sizes2 = (ngx_rtmp_mp4_sizes2_t *) pos; + + if (pos + sizeof(*t->sizes) + ngx_rtmp_r32(t->sizes2->sample_count) * + ngx_rtmp_r32(t->sizes2->field_size) / 8 + <= last) + { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: sizes2 field_size=%uD entries=%uD", + ngx_rtmp_r32(t->sizes2->field_size), + ngx_rtmp_r32(t->sizes2->sample_count)); + return NGX_OK; + } + + t->sizes2 = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_stco(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->offsets = (ngx_rtmp_mp4_offsets_t *) pos; + + if (pos + sizeof(*t->offsets) + ngx_rtmp_r32(t->offsets->entry_count) * + sizeof(t->offsets->entries[0]) + <= last) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: offsets entries=%uD", + ngx_rtmp_r32(t->offsets->entry_count)); + return NGX_OK; + } + + t->offsets = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse_co64(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + t = ctx->track; + + if (t == NULL) { + return NGX_OK; + } + + t->offsets64 = (ngx_rtmp_mp4_offsets64_t *) pos; + + if (pos + sizeof(*t->offsets64) + ngx_rtmp_r32(t->offsets64->entry_count) * + sizeof(t->offsets64->entries[0]) + <= last) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: offsets64 entries=%uD", + ngx_rtmp_r32(t->offsets64->entry_count)); + return NGX_OK; + } + + t->offsets64 = NULL; + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_parse(ngx_rtmp_session_t *s, u_char *pos, u_char *last) +{ + uint32_t *hdr, tag; + size_t size, nboxes; + ngx_uint_t n; + ngx_rtmp_mp4_box_t *b; + + while (pos != last) { + if (pos + 8 > last) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: too small box: size=%i", last - pos); + return NGX_ERROR; + } + + hdr = (uint32_t *) pos; + size = ngx_rtmp_r32(hdr[0]); + tag = hdr[1]; + + if (pos + size > last) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "mp4: too big box '%*s': size=%uz", + 4, &tag, size); + return NGX_ERROR; + } + + b = ngx_rtmp_mp4_boxes; + nboxes = sizeof(ngx_rtmp_mp4_boxes) / sizeof(ngx_rtmp_mp4_boxes[0]); + + for (n = 0; n < nboxes && b->tag != tag; ++n, ++b); + + if (n == nboxes) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: box unhandled '%*s'", 4, &tag); + } else { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: box '%*s'", 4, &tag); + b->handler(s, pos + 8, pos + size); + } + + pos += size; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_next_time(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_time_entry_t *te; + + if (t->times == NULL) { + return NGX_ERROR; + } + + cr = &t->cursor; + + if (cr->time_pos >= ngx_rtmp_r32(t->times->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui time[%ui/%uD] overflow", + t->id, cr->time_pos, + ngx_rtmp_r32(t->times->entry_count)); + + return NGX_ERROR; + } + + te = &t->times->entries[cr->time_pos]; + + cr->last_timestamp = cr->timestamp; + cr->timestamp += ngx_rtmp_r32(te->sample_delta); + + cr->not_first = 1; + + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui time[%ui] [%ui/%uD][%ui/%uD]=%uD t=%uD", + t->id, cr->pos, cr->time_pos, + ngx_rtmp_r32(t->times->entry_count), + cr->time_count, ngx_rtmp_r32(te->sample_count), + ngx_rtmp_r32(te->sample_delta), + cr->timestamp); + + cr->time_count++; + cr->pos++; + + if (cr->time_count >= ngx_rtmp_r32(te->sample_count)) { + cr->time_pos++; + cr->time_count = 0; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek_time(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t, + uint32_t timestamp) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_time_entry_t *te; + uint32_t dt; + + if (t->times == NULL) { + return NGX_ERROR; + } + + cr = &t->cursor; + + te = t->times->entries; + + while (cr->time_pos < ngx_rtmp_r32(t->times->entry_count)) { + dt = ngx_rtmp_r32(te->sample_delta) * ngx_rtmp_r32(te->sample_count); + + if (cr->timestamp + dt >= timestamp) { + if (te->sample_delta == 0) { + return NGX_ERROR; + } + + cr->time_count = (timestamp - cr->timestamp) / + ngx_rtmp_r32(te->sample_delta); + cr->timestamp += ngx_rtmp_r32(te->sample_delta) * cr->time_count; + cr->pos += cr->time_count; + + break; + } + + cr->timestamp += dt; + cr->pos += ngx_rtmp_r32(te->sample_count); + cr->time_pos++; + te++; + } + + if (cr->time_pos >= ngx_rtmp_r32(t->times->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek time[%ui/%uD] overflow", + t->id, cr->time_pos, + ngx_rtmp_r32(t->times->entry_count)); + + return NGX_ERROR; + } + + ngx_log_debug8(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek time[%ui] [%ui/%uD][%ui/%uD]=%uD " + "t=%uD", + t->id, cr->pos, cr->time_pos, + ngx_rtmp_r32(t->times->entry_count), + cr->time_count, + ngx_rtmp_r32(te->sample_count), + ngx_rtmp_r32(te->sample_delta), + cr->timestamp); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_update_offset(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_uint_t chunk; + + cr = &t->cursor; + + if (cr->chunk < 1) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui offset[%ui] underflow", + t->id, cr->chunk); + return NGX_ERROR; + } + + chunk = cr->chunk - 1; + + if (t->offsets) { + if (chunk >= ngx_rtmp_r32(t->offsets->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui offset[%ui/%uD] overflow", + t->id, cr->chunk, + ngx_rtmp_r32(t->offsets->entry_count)); + + return NGX_ERROR; + } + + cr->offset = (off_t) ngx_rtmp_r32(t->offsets->entries[chunk]); + cr->size = 0; + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui offset[%ui/%uD]=%O", + t->id, cr->chunk, + ngx_rtmp_r32(t->offsets->entry_count), + cr->offset); + + return NGX_OK; + } + + if (t->offsets64) { + if (chunk >= ngx_rtmp_r32(t->offsets64->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui offset64[%ui/%uD] overflow", + t->id, cr->chunk, + ngx_rtmp_r32(t->offsets->entry_count)); + + return NGX_ERROR; + } + + cr->offset = (off_t) ngx_rtmp_r64(t->offsets64->entries[chunk]); + cr->size = 0; + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui offset64[%ui/%uD]=%O", + t->id, cr->chunk, + ngx_rtmp_r32(t->offsets->entry_count), + cr->offset); + + return NGX_OK; + } + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_next_chunk(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_chunk_entry_t *ce, *nce; + ngx_int_t new_chunk; + + if (t->chunks == NULL) { + return NGX_OK; + } + + cr = &t->cursor; + + if (cr->chunk_pos >= ngx_rtmp_r32(t->chunks->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui chunk[%ui/%uD] overflow", + t->id, cr->chunk_pos, + ngx_rtmp_r32(t->chunks->entry_count)); + + return NGX_ERROR; + } + + ce = &t->chunks->entries[cr->chunk_pos]; + + cr->chunk_count++; + + if (cr->chunk_count >= ngx_rtmp_r32(ce->samples_per_chunk)) { + cr->chunk_count = 0; + cr->chunk++; + + if (cr->chunk_pos + 1 < ngx_rtmp_r32(t->chunks->entry_count)) { + nce = ce + 1; + if (cr->chunk >= ngx_rtmp_r32(nce->first_chunk)) { + cr->chunk_pos++; + ce = nce; + } + } + + new_chunk = 1; + + } else { + new_chunk = 0; + } + + ngx_log_debug7(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui chunk[%ui/%uD][%uD..%ui][%ui/%uD]", + t->id, cr->chunk_pos, + ngx_rtmp_r32(t->chunks->entry_count), + ngx_rtmp_r32(ce->first_chunk), + cr->chunk, cr->chunk_count, + ngx_rtmp_r32(ce->samples_per_chunk)); + + + if (new_chunk) { + return ngx_rtmp_mp4_update_offset(s, t); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek_chunk(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_chunk_entry_t *ce, *nce; + ngx_uint_t pos, dpos, dchunk; + + cr = &t->cursor; + + if (t->chunks == NULL || t->chunks->entry_count == 0) { + cr->chunk = 1; + return NGX_OK; + } + + ce = t->chunks->entries; + pos = 0; + + while (cr->chunk_pos + 1 < ngx_rtmp_r32(t->chunks->entry_count)) { + nce = ce + 1; + + dpos = (ngx_rtmp_r32(nce->first_chunk) - + ngx_rtmp_r32(ce->first_chunk)) * + ngx_rtmp_r32(ce->samples_per_chunk); + + if (pos + dpos > cr->pos) { + break; + } + + pos += dpos; + ce++; + cr->chunk_pos++; + } + + if (ce->samples_per_chunk == 0) { + return NGX_ERROR; + } + + dchunk = (cr->pos - pos) / ngx_rtmp_r32(ce->samples_per_chunk); + + cr->chunk = ngx_rtmp_r32(ce->first_chunk) + dchunk; + cr->chunk_pos = (ngx_uint_t) (ce - t->chunks->entries); + cr->chunk_count = (ngx_uint_t) (cr->pos - pos - dchunk * + ngx_rtmp_r32(ce->samples_per_chunk)); + + ngx_log_debug7(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek chunk[%ui/%uD][%uD..%ui][%ui/%uD]", + t->id, cr->chunk_pos, + ngx_rtmp_r32(t->chunks->entry_count), + ngx_rtmp_r32(ce->first_chunk), + cr->chunk, cr->chunk_count, + ngx_rtmp_r32(ce->samples_per_chunk)); + + return ngx_rtmp_mp4_update_offset(s, t); +} + + +static ngx_int_t +ngx_rtmp_mp4_next_size(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + + cr = &t->cursor; + + cr->offset += cr->size; + + if (t->sizes) { + if (t->sizes->sample_size) { + cr->size = ngx_rtmp_r32(t->sizes->sample_size); + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui size fix=%uz", + t->id, cr->size); + + return NGX_OK; + } + + cr->size_pos++; + + if (cr->size_pos >= ngx_rtmp_r32(t->sizes->sample_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui size[%ui/%uD] overflow", + t->id, cr->size_pos, + ngx_rtmp_r32(t->sizes->sample_count)); + + return NGX_ERROR; + } + + cr->size = ngx_rtmp_r32(t->sizes->entries[cr->size_pos]); + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui size[%ui/%uD]=%uz", + t->id, cr->size_pos, + ngx_rtmp_r32(t->sizes->sample_count), + cr->size); + + return NGX_OK; + } + + if (t->sizes2) { + if (cr->size_pos >= ngx_rtmp_r32(t->sizes2->sample_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui size[%ui/%uD] overflow", + t->id, cr->size_pos, + ngx_rtmp_r32(t->sizes2->sample_count)); + + return NGX_ERROR; + } + + /*TODO*/ + + return NGX_OK; + } + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek_size(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_uint_t pos; + + cr = &t->cursor; + + if (cr->chunk_count > cr->pos) { + return NGX_ERROR; + } + + if (t->sizes) { + if (t->sizes->sample_size) { + cr->size = ngx_rtmp_r32(t->sizes->sample_size); + + cr->offset += cr->size * cr->chunk_count; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek size fix=%uz", + t->id, cr->size); + + return NGX_OK; + } + + if (cr->pos >= ngx_rtmp_r32(t->sizes->sample_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek size[%ui/%uD] overflow", + t->id, cr->pos, + ngx_rtmp_r32(t->sizes->sample_count)); + + return NGX_ERROR; + } + + for (pos = 1; pos <= cr->chunk_count; ++pos) { + cr->offset += ngx_rtmp_r32(t->sizes->entries[cr->pos - pos]); + } + + cr->size_pos = cr->pos; + cr->size = ngx_rtmp_r32(t->sizes->entries[cr->size_pos]); + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek size[%ui/%uD]=%uz", + t->id, cr->size_pos, + ngx_rtmp_r32(t->sizes->sample_count), + cr->size); + + return NGX_OK; + } + + if (t->sizes2) { + if (cr->size_pos >= ngx_rtmp_r32(t->sizes2->sample_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek size2[%ui/%uD] overflow", + t->id, cr->size_pos, + ngx_rtmp_r32(t->sizes->sample_count)); + + return NGX_ERROR; + } + + cr->size_pos = cr->pos; + + /* TODO */ + return NGX_OK; + } + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_mp4_next_key(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + uint32_t *ke; + + cr = &t->cursor; + + if (t->keys == NULL) { + return NGX_OK; + } + + if (cr->key) { + cr->key_pos++; + } + + if (cr->key_pos >= ngx_rtmp_r32(t->keys->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui key[%ui/%uD] overflow", + t->id, cr->key_pos, + ngx_rtmp_r32(t->keys->entry_count)); + + cr->key = 0; + + return NGX_OK; + } + + ke = &t->keys->entries[cr->key_pos]; + cr->key = (cr->pos + 1 == ngx_rtmp_r32(*ke)); + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui key[%ui/%uD][%ui/%uD]=%s", + t->id, cr->key_pos, + ngx_rtmp_r32(t->keys->entry_count), + cr->pos, ngx_rtmp_r32(*ke), + cr->key ? "match" : "miss"); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek_key(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + uint32_t *ke; + ngx_int_t dpos; + + cr = &t->cursor; + + if (t->keys == NULL) { + return NGX_OK; + } + + while (cr->key_pos < ngx_rtmp_r32(t->keys->entry_count)) { + if (ngx_rtmp_r32(t->keys->entries[cr->key_pos]) > cr->pos) { + break; + } + + cr->key_pos++; + } + + if (cr->key_pos >= ngx_rtmp_r32(t->keys->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek key[%ui/%uD] overflow", + t->id, cr->key_pos, + ngx_rtmp_r32(t->keys->entry_count)); + return NGX_OK; + } + + ke = &t->keys->entries[cr->key_pos]; + /*cr->key = (cr->pos + 1 == ngx_rtmp_r32(*ke));*/ + + /* distance to the next keyframe */ + dpos = ngx_rtmp_r32(*ke) - cr->pos - 1; + cr->key = 1; + + /* TODO: range version needed */ + for (; dpos > 0; --dpos) { + ngx_rtmp_mp4_next_time(s, t); + } + +/* cr->key = (cr->pos + 1 == ngx_rtmp_r32(*ke));*/ + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek key[%ui/%uD][%ui/%uD]=%s", + t->id, cr->key_pos, + ngx_rtmp_r32(t->keys->entry_count), + cr->pos, ngx_rtmp_r32(*ke), + cr->key ? "match" : "miss"); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_next_delay(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_delay_entry_t *de; + + cr = &t->cursor; + + if (t->delays == NULL) { + return NGX_OK; + } + + if (cr->delay_pos >= ngx_rtmp_r32(t->delays->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui delay[%ui/%uD] overflow", + t->id, cr->delay_pos, + ngx_rtmp_r32(t->delays->entry_count)); + + return NGX_OK; + } + + cr->delay_count++; + de = &t->delays->entries[cr->delay_pos]; + + if (cr->delay_count >= ngx_rtmp_r32(de->sample_count)) { + cr->delay_pos++; + de++; + cr->delay_count = 0; + } + + if (cr->delay_pos >= ngx_rtmp_r32(t->delays->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui delay[%ui/%uD] overflow", + t->id, cr->delay_pos, + ngx_rtmp_r32(t->delays->entry_count)); + + return NGX_OK; + } + + cr->delay = ngx_rtmp_r32(de->sample_offset); + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui delay[%ui/%uD][%ui/%uD]=%ui", + t->id, cr->delay_pos, + ngx_rtmp_r32(t->delays->entry_count), + cr->delay_count, + ngx_rtmp_r32(de->sample_count), cr->delay); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek_delay(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_delay_entry_t *de; + uint32_t pos, dpos; + + cr = &t->cursor; + + if (t->delays == NULL) { + return NGX_OK; + } + + pos = 0; + de = t->delays->entries; + + while (cr->delay_pos < ngx_rtmp_r32(t->delays->entry_count)) { + dpos = ngx_rtmp_r32(de->sample_count); + + if (pos + dpos > cr->pos) { + cr->delay_count = cr->pos - pos; + cr->delay = ngx_rtmp_r32(de->sample_offset); + break; + } + + cr->delay_pos++; + pos += dpos; + de++; + } + + if (cr->delay_pos >= ngx_rtmp_r32(t->delays->entry_count)) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek delay[%ui/%uD] overflow", + t->id, cr->delay_pos, + ngx_rtmp_r32(t->delays->entry_count)); + + return NGX_OK; + } + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek delay[%ui/%uD][%ui/%uD]=%ui", + t->id, cr->delay_pos, + ngx_rtmp_r32(t->delays->entry_count), + cr->delay_count, + ngx_rtmp_r32(de->sample_count), cr->delay); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_next(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t) +{ + if (ngx_rtmp_mp4_next_time(s, t) != NGX_OK || + ngx_rtmp_mp4_next_key(s, t) != NGX_OK || + ngx_rtmp_mp4_next_chunk(s, t) != NGX_OK || + ngx_rtmp_mp4_next_size(s, t) != NGX_OK || + ngx_rtmp_mp4_next_delay(s, t) != NGX_OK) + { + t->cursor.valid = 0; + return NGX_ERROR; + } + + t->cursor.valid = 1; + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_send_meta(ngx_rtmp_session_t *s) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_int_t rc; + ngx_uint_t n; + ngx_rtmp_header_t h; + ngx_chain_t *out; + ngx_rtmp_mp4_track_t *t; + double d; + + static struct { + double width; + double height; + double duration; + double video_codec_id; + double audio_codec_id; + double audio_sample_rate; + } v; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_string("width"), + &v.width, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("height"), + &v.height, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("displayWidth"), + &v.width, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("displayHeight"), + &v.height, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("duration"), + &v.duration, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videocodecid"), + &v.video_codec_id, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiocodecid"), + &v.audio_codec_id, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audiosamplerate"), + &v.audio_sample_rate, 0 }, + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onMetaData", 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, sizeof(out_inf) }, + }; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + if (ctx == NULL) { + return NGX_OK; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + ngx_memzero(&v, sizeof(v)); + + v.width = ctx->width; + v.height = ctx->height; + v.audio_sample_rate = ctx->sample_rate; + + t = &ctx->tracks[0]; + for (n = 0; n < ctx->ntracks; ++n, ++t) { + d = ngx_rtmp_mp4_to_rtmp_timestamp(t, t->duration) / 1000.; + + if (v.duration < d) { + v.duration = d; + } + + switch (t->type) { + case NGX_RTMP_MSG_AUDIO: + v.audio_codec_id = t->codec; + break; + case NGX_RTMP_MSG_VIDEO: + v.video_codec_id = t->codec; + break; + } + } + + out = NULL; + rc = ngx_rtmp_append_amf(s, &out, NULL, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); + if (rc != NGX_OK || out == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&h, sizeof(h)); + + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + h.type = NGX_RTMP_MSG_AMF_META; + + ngx_rtmp_prepare_message(s, &h, NULL, out); + rc = ngx_rtmp_send_message(s, out, 0); + ngx_rtmp_free_shared_chain(cscf, out); + + return rc; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek_track(ngx_rtmp_session_t *s, ngx_rtmp_mp4_track_t *t, + ngx_int_t timestamp) +{ + ngx_rtmp_mp4_cursor_t *cr; + + cr = &t->cursor; + ngx_memzero(cr, sizeof(*cr)); + + if (ngx_rtmp_mp4_seek_time(s, t, ngx_rtmp_mp4_from_rtmp_timestamp( + t, timestamp)) != NGX_OK || + ngx_rtmp_mp4_seek_key(s, t) != NGX_OK || + ngx_rtmp_mp4_seek_chunk(s, t) != NGX_OK || + ngx_rtmp_mp4_seek_size(s, t) != NGX_OK || + ngx_rtmp_mp4_seek_delay(s, t) != NGX_OK) + { + return NGX_ERROR; + } + + cr->valid = 1; + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_send(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_uint_t *ts) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_buf_t in_buf; + ngx_rtmp_header_t h, lh; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_chain_t *out, in; + ngx_rtmp_mp4_track_t *t, *cur_t; + ngx_rtmp_mp4_cursor_t *cr, *cur_cr; + uint32_t buflen, end_timestamp, + timestamp, last_timestamp, rdelay, + cur_timestamp; + ssize_t ret; + u_char fhdr[5]; + size_t fhdr_size; + ngx_int_t rc; + ngx_uint_t n, counter; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + if (!ctx->meta_sent) { + rc = ngx_rtmp_mp4_send_meta(s); + + if (rc == NGX_OK) { + ctx->meta_sent = 1; + } + + return rc; + } + + buflen = s->buflen + NGX_RTMP_MP4_BUFLEN_ADDON; + + counter = 0; + last_timestamp = 0; + end_timestamp = ctx->start_timestamp + + (ngx_current_msec - ctx->epoch) + buflen; + + for ( ;; ) { + counter++; + if (counter > NGX_RTMP_MP4_MAX_FRAMES) { + return NGX_OK; + } + + timestamp = 0; + t = NULL; + + for (n = 0; n < ctx->ntracks; n++) { + cur_t = &ctx->tracks[n]; + cur_cr = &cur_t->cursor; + + if (!cur_cr->valid) { + continue; + } + + cur_timestamp = ngx_rtmp_mp4_to_rtmp_timestamp(cur_t, + cur_cr->timestamp); + + if (t == NULL || cur_timestamp < timestamp) { + timestamp = cur_timestamp; + t = cur_t; + } + } + + if (t == NULL) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "mp4: no track"); + return NGX_DONE; + } + + if (timestamp > end_timestamp) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui ahead %uD > %uD", + t->id, timestamp, end_timestamp); + + if (ts) { + *ts = last_timestamp; + } + + return (uint32_t) (timestamp - end_timestamp); + } + + cr = &t->cursor; + + last_timestamp = ngx_rtmp_mp4_to_rtmp_timestamp(t, cr->last_timestamp); + + ngx_memzero(&h, sizeof(h)); + + h.msid = NGX_RTMP_MSID; + h.type = (uint8_t) t->type; + h.csid = t->csid; + + lh = h; + + h.timestamp = timestamp; + lh.timestamp = last_timestamp; + + ngx_memzero(&in, sizeof(in)); + ngx_memzero(&in_buf, sizeof(in_buf)); + + if (t->header && !t->header_sent) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui sending header of size=%uz", + t->id, t->header_size); + + fhdr[0] = t->fhdr; + fhdr[1] = 0; + + if (t->type == NGX_RTMP_MSG_VIDEO) { + fhdr[0] |= 0x10; + fhdr[2] = fhdr[3] = fhdr[4] = 0; + fhdr_size = 5; + } else { + fhdr_size = 2; + } + + in.buf = &in_buf; + in_buf.pos = fhdr; + in_buf.last = fhdr + fhdr_size; + + out = ngx_rtmp_append_shared_bufs(cscf, NULL, &in); + + in.buf = &in_buf; + in_buf.pos = t->header; + in_buf.last = t->header + t->header_size; + + ngx_rtmp_append_shared_bufs(cscf, out, &in); + + ngx_rtmp_prepare_message(s, &h, NULL, out); + rc = ngx_rtmp_send_message(s, out, 0); + ngx_rtmp_free_shared_chain(cscf, out); + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + t->header_sent = 1; + } + + ngx_log_debug5(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui read frame offset=%O, size=%uz, " + "timestamp=%uD, last_timestamp=%uD", + t->id, cr->offset, cr->size, timestamp, + last_timestamp); + + ngx_rtmp_mp4_buffer[0] = t->fhdr; + fhdr_size = 1; + + if (t->type == NGX_RTMP_MSG_VIDEO) { + if (cr->key) { + ngx_rtmp_mp4_buffer[0] |= 0x10; + } else if (cr->delay) { + ngx_rtmp_mp4_buffer[0] |= 0x20; + } else { + ngx_rtmp_mp4_buffer[0] |= 0x30; + } + + if (t->header) { + fhdr_size = 5; + + rdelay = ngx_rtmp_mp4_to_rtmp_timestamp(t, cr->delay); + + ngx_rtmp_mp4_buffer[1] = 1; + ngx_rtmp_mp4_buffer[2] = (rdelay >> 16) & 0xff; + ngx_rtmp_mp4_buffer[3] = (rdelay >> 8) & 0xff; + ngx_rtmp_mp4_buffer[4] = rdelay & 0xff; + } + + } else { /* NGX_RTMP_MSG_AUDIO */ + if (t->header) { + fhdr_size = 2; + ngx_rtmp_mp4_buffer[1] = 1; + } + } + + if (cr->size + fhdr_size > sizeof(ngx_rtmp_mp4_buffer)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "mp4: track#%ui too big frame: %D>%uz", + t->id, cr->size, sizeof(ngx_rtmp_mp4_buffer)); + goto next; + } + + ret = ngx_read_file(f, ngx_rtmp_mp4_buffer + fhdr_size, + cr->size, cr->offset); + + if (ret != (ssize_t) cr->size) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "mp4: track#%ui could not read frame", t->id); + goto next; + } + + in.buf = &in_buf; + in_buf.pos = ngx_rtmp_mp4_buffer; + in_buf.last = ngx_rtmp_mp4_buffer + cr->size + fhdr_size; + + out = ngx_rtmp_append_shared_bufs(cscf, NULL, &in); + + ngx_rtmp_prepare_message(s, &h, cr->not_first ? &lh : NULL, out); + rc = ngx_rtmp_send_message(s, out, 0); + ngx_rtmp_free_shared_chain(cscf, out); + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + s->current_time = timestamp; + +next: + if (ngx_rtmp_mp4_next(s, t) != NGX_OK) { + return NGX_DONE; + } + } +} + + +static ngx_int_t +ngx_rtmp_mp4_init(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_int_t aindex, + ngx_int_t vindex) +{ + ngx_rtmp_mp4_ctx_t *ctx; + uint32_t hdr[2]; + ssize_t n; + size_t offset, page_offset, size, shift; + uint64_t extended_size; + ngx_file_info_t fi; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL) { + ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_mp4_ctx_t)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_mp4_module); + } + + ngx_memzero(ctx, sizeof(*ctx)); + + ctx->aindex = aindex; + ctx->vindex = vindex; + + offset = 0; + size = 0; + + for ( ;; ) { + n = ngx_read_file(f, (u_char *) &hdr, sizeof(hdr), offset); + + if (n != sizeof(hdr)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "mp4: error reading file at offset=%uz " + "while searching for moov box", offset); + return NGX_ERROR; + } + + size = (size_t) ngx_rtmp_r32(hdr[0]); + shift = sizeof(hdr); + + if (size == 1) { + n = ngx_read_file(f, (u_char *) &extended_size, + sizeof(extended_size), offset + sizeof(hdr)); + + if (n != sizeof(extended_size)) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "mp4: error reading file at offset=%uz " + "while searching for moov box", offset + 8); + return NGX_ERROR; + } + + size = (size_t) ngx_rtmp_r64(extended_size); + shift += sizeof(extended_size); + + } else if (size == 0) { + if (ngx_fd_info(f->fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "mp4: " ngx_fd_info_n " failed"); + return NGX_ERROR; + } + size = ngx_file_size(&fi) - offset; + } + + if (hdr[1] == ngx_rtmp_mp4_make_tag('m','o','o','v')) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: found moov box"); + break; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: skipping box '%*s'", 4, hdr + 1); + + offset += size; + } + + if (size < shift) { + return NGX_ERROR; + } + + size -= shift; + offset += shift; + + page_offset = offset & (ngx_pagesize - 1); + ctx->mmaped_size = page_offset + size; + + ctx->mmaped = ngx_rtmp_mp4_mmap(f->fd, ctx->mmaped_size, + offset - page_offset, &ctx->extra); + if (ctx->mmaped == NULL) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "mp4: mmap failed at offset=%ui, size=%uz", + offset, size); + return NGX_ERROR; + } + + return ngx_rtmp_mp4_parse(s, (u_char *) ctx->mmaped + page_offset, + (u_char *) ctx->mmaped + page_offset + size); +} + + +static ngx_int_t +ngx_rtmp_mp4_done(ngx_rtmp_session_t *s, ngx_file_t *f) +{ + ngx_rtmp_mp4_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL || ctx->mmaped == NULL) { + return NGX_OK; + } + + if (ngx_rtmp_mp4_munmap(ctx->mmaped, ctx->mmaped_size, &ctx->extra) + != NGX_OK) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "mp4: munmap failed"); + return NGX_ERROR; + } + + ctx->mmaped = NULL; + ctx->mmaped_size = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_seek(ngx_rtmp_session_t *s, ngx_file_t *f, ngx_uint_t timestamp) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_track_t *t; + ngx_uint_t n; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: seek timestamp=%ui", timestamp); + + for (n = 0; n < ctx->ntracks; ++n) { + t = &ctx->tracks[n]; + + if (t->type != NGX_RTMP_MSG_VIDEO) { + continue; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek video", n); + + ngx_rtmp_mp4_seek_track(s, t, timestamp); + + timestamp = ngx_rtmp_mp4_to_rtmp_timestamp(t, t->cursor.timestamp); + + break; + } + + for (n = 0; n < ctx->ntracks; ++n) { + t = &ctx->tracks[n]; + + if (t->type == NGX_RTMP_MSG_VIDEO) { + continue; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: track#%ui seek", n); + + ngx_rtmp_mp4_seek_track(s, &ctx->tracks[n], timestamp); + } + + ctx->start_timestamp = timestamp; + ctx->epoch = ngx_current_msec; + + return ngx_rtmp_mp4_reset(s); +} + + +static ngx_int_t +ngx_rtmp_mp4_start(ngx_rtmp_session_t *s, ngx_file_t *f) +{ + ngx_rtmp_mp4_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: start timestamp=%uD", ctx->start_timestamp); + + ctx->epoch = ngx_current_msec; + + return NGX_OK;/*ngx_rtmp_mp4_reset(s);*/ +} + + +static ngx_int_t +ngx_rtmp_mp4_reset(ngx_rtmp_session_t *s) +{ + ngx_rtmp_mp4_ctx_t *ctx; + ngx_rtmp_mp4_cursor_t *cr; + ngx_rtmp_mp4_track_t *t; + ngx_uint_t n; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL) { + return NGX_OK; + } + + t = &ctx->tracks[0]; + for (n = 0; n < ctx->ntracks; ++n, ++t) { + cr = &t->cursor; + cr->not_first = 0; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_mp4_stop(ngx_rtmp_session_t *s, ngx_file_t *f) +{ + ngx_rtmp_mp4_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_mp4_module); + + if (ctx == NULL) { + return NGX_OK; + } + + ctx->start_timestamp += (ngx_current_msec - ctx->epoch); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "mp4: stop timestamp=%uD", ctx->start_timestamp); + + return NGX_OK;/*ngx_rtmp_mp4_reset(s);*/ +} + + +static ngx_int_t +ngx_rtmp_mp4_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_play_main_conf_t *pmcf; + ngx_rtmp_play_fmt_t **pfmt, *fmt; + + pmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_play_module); + + pfmt = ngx_array_push(&pmcf->fmts); + + if (pfmt == NULL) { + return NGX_ERROR; + } + + fmt = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_play_fmt_t)); + + if (fmt == NULL) { + return NGX_ERROR; + } + + *pfmt = fmt; + + ngx_str_set(&fmt->name, "mp4-format"); + + ngx_str_set(&fmt->pfx, "mp4:"); + ngx_str_set(&fmt->sfx, ".mp4"); + + fmt->init = ngx_rtmp_mp4_init; + fmt->done = ngx_rtmp_mp4_done; + fmt->seek = ngx_rtmp_mp4_seek; + fmt->start = ngx_rtmp_mp4_start; + fmt->stop = ngx_rtmp_mp4_stop; + fmt->send = ngx_rtmp_mp4_send; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c new file mode 100644 index 0000000..f772c72 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c @@ -0,0 +1,725 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_netcall_module.h" + + +static ngx_int_t ngx_rtmp_netcall_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_netcall_create_srv_conf(ngx_conf_t *cf); +static char * ngx_rtmp_netcall_merge_srv_conf(ngx_conf_t *cf, + void *parent, void *child); + +static void ngx_rtmp_netcall_close(ngx_connection_t *cc); +static void ngx_rtmp_netcall_detach(ngx_connection_t *cc); + +static void ngx_rtmp_netcall_recv(ngx_event_t *rev); +static void ngx_rtmp_netcall_send(ngx_event_t *wev); + + +typedef struct { + ngx_msec_t timeout; + size_t bufsize; + ngx_log_t *log; +} ngx_rtmp_netcall_srv_conf_t; + + +typedef struct ngx_rtmp_netcall_session_s { + ngx_rtmp_session_t *session; + ngx_peer_connection_t *pc; + ngx_url_t *url; + struct ngx_rtmp_netcall_session_s *next; + void *arg; + ngx_rtmp_netcall_handle_pt handle; + ngx_rtmp_netcall_filter_pt filter; + ngx_rtmp_netcall_sink_pt sink; + ngx_chain_t *in; + ngx_chain_t *inlast; + ngx_chain_t *out; + ngx_msec_t timeout; + unsigned detached:1; + size_t bufsize; +} ngx_rtmp_netcall_session_t; + + +typedef struct { + ngx_rtmp_netcall_session_t *cs; +} ngx_rtmp_netcall_ctx_t; + + +static ngx_command_t ngx_rtmp_netcall_commands[] = { + + { ngx_string("netcall_timeout"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_netcall_srv_conf_t, timeout), + NULL }, + + { ngx_string("netcall_buffer"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_SRV_CONF_OFFSET, + offsetof(ngx_rtmp_netcall_srv_conf_t, bufsize), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_netcall_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_netcall_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + ngx_rtmp_netcall_create_srv_conf, /* create server configuration */ + ngx_rtmp_netcall_merge_srv_conf, /* merge server configuration */ + NULL, /* create app configuration */ + NULL /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_netcall_module = { + NGX_MODULE_V1, + &ngx_rtmp_netcall_module_ctx, /* module context */ + ngx_rtmp_netcall_commands, /* module directives */ + NGX_RTMP_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_rtmp_netcall_create_srv_conf(ngx_conf_t *cf) +{ + ngx_rtmp_netcall_srv_conf_t *nscf; + + nscf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_netcall_srv_conf_t)); + if (nscf == NULL) { + return NULL; + } + + nscf->timeout = NGX_CONF_UNSET_MSEC; + nscf->bufsize = NGX_CONF_UNSET_SIZE; + + nscf->log = &cf->cycle->new_log; + + return nscf; +} + + +static char * +ngx_rtmp_netcall_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_netcall_srv_conf_t *prev = parent; + ngx_rtmp_netcall_srv_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 10000); + ngx_conf_merge_size_value(conf->bufsize, prev->bufsize, 1024); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_netcall_disconnect(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_netcall_ctx_t *ctx; + ngx_rtmp_netcall_session_t *cs; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_netcall_module); + + if (ctx) { + for (cs = ctx->cs; cs; cs = cs->next) { + ngx_rtmp_netcall_detach(cs->pc->connection); + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_netcall_get_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_rtmp_netcall_session_t *cs = data; + + pc->sockaddr =(struct sockaddr *)&cs->url->sockaddr; + pc->socklen = cs->url->socklen; + pc->name = &cs->url->host; + + return NGX_OK; +} + + +static void +ngx_rtmp_netcall_free_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state) +{ +} + + +ngx_int_t +ngx_rtmp_netcall_create(ngx_rtmp_session_t *s, ngx_rtmp_netcall_init_t *ci) +{ + ngx_rtmp_netcall_ctx_t *ctx; + ngx_peer_connection_t *pc; + ngx_rtmp_netcall_session_t *cs; + ngx_rtmp_netcall_srv_conf_t *nscf; + ngx_connection_t *c, *cc; + ngx_pool_t *pool; + ngx_int_t rc; + + pool = NULL; + c = s->connection; + + nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_netcall_module); + if (nscf == NULL) { + goto error; + } + + /* get module context */ + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_netcall_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(c->pool, + sizeof(ngx_rtmp_netcall_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_netcall_module); + } + + /* Create netcall pool, connection, session. + * Note we use shared (app-wide) log because + * s->connection->log might be unavailable + * in detached netcall when it's being closed */ + pool = ngx_create_pool(4096, nscf->log); + if (pool == NULL) { + goto error; + } + + pc = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t)); + if (pc == NULL) { + goto error; + } + + cs = ngx_pcalloc(pool, sizeof(ngx_rtmp_netcall_session_t)); + if (cs == NULL) { + goto error; + } + + /* copy arg to connection pool */ + if (ci->argsize) { + cs->arg = ngx_pcalloc(pool, ci->argsize); + if (cs->arg == NULL) { + goto error; + } + ngx_memcpy(cs->arg, ci->arg, ci->argsize); + } + + cs->timeout = nscf->timeout; + cs->bufsize = nscf->bufsize; + cs->url = ci->url; + cs->session = s; + cs->filter = ci->filter; + cs->sink = ci->sink; + cs->handle = ci->handle; + if (cs->handle == NULL) { + cs->detached = 1; + } + + pc->log = nscf->log; + pc->get = ngx_rtmp_netcall_get_peer; + pc->free = ngx_rtmp_netcall_free_peer; + pc->data = cs; + + /* connect */ + rc = ngx_event_connect_peer(pc); + if (rc != NGX_OK && rc != NGX_AGAIN ) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "netcall: connection failed"); + goto error; + } + + cc = pc->connection; + cc->data = cs; + cc->pool = pool; + cs->pc = pc; + + cs->out = ci->create(s, ci->arg, pool); + if (cs->out == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "netcall: creation failed"); + ngx_close_connection(pc->connection); + goto error; + } + + cc->write->handler = ngx_rtmp_netcall_send; + cc->read->handler = ngx_rtmp_netcall_recv; + + if (!cs->detached) { + cs->next = ctx->cs; + ctx->cs = cs; + } + + ngx_rtmp_netcall_send(cc->write); + + return c->destroyed ? NGX_ERROR : NGX_OK; + +error: + if (pool) { + ngx_destroy_pool(pool); + } + + return NGX_ERROR; +} + + +static void +ngx_rtmp_netcall_close(ngx_connection_t *cc) +{ + ngx_rtmp_netcall_session_t *cs, **css; + ngx_pool_t *pool; + ngx_rtmp_session_t *s; + ngx_rtmp_netcall_ctx_t *ctx; + ngx_buf_t *b; + + cs = cc->data; + + if (cc->destroyed) { + return; + } + + cc->destroyed = 1; + + if (!cs->detached) { + s = cs->session; + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_netcall_module); + + if (cs->in && cs->sink) { + cs->sink(cs->session, cs->in); + + b = cs->in->buf; + b->pos = b->last = b->start; + + } + + for(css = &ctx->cs; *css; css = &((*css)->next)) { + if (*css == cs) { + *css = cs->next; + break; + } + } + + if (cs->handle && cs->handle(s, cs->arg, cs->in) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + } + + pool = cc->pool; + ngx_close_connection(cc); + ngx_destroy_pool(pool); +} + + +static void +ngx_rtmp_netcall_detach(ngx_connection_t *cc) +{ + ngx_rtmp_netcall_session_t *cs; + + cs = cc->data; + cs->detached = 1; +} + + +static void +ngx_rtmp_netcall_recv(ngx_event_t *rev) +{ + ngx_rtmp_netcall_session_t *cs; + ngx_connection_t *cc; + ngx_chain_t *cl; + ngx_int_t n; + ngx_buf_t *b; + + cc = rev->data; + cs = cc->data; + + if (cc->destroyed) { + return; + } + + if (rev->timedout) { + cc->timedout = 1; + ngx_rtmp_netcall_close(cc); + return; + } + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + for ( ;; ) { + + if (cs->inlast == NULL || + cs->inlast->buf->last == cs->inlast->buf->end) + { + if (cs->in && cs->sink) { + if (!cs->detached) { + if (cs->sink(cs->session, cs->in) != NGX_OK) { + ngx_rtmp_netcall_close(cc); + return; + } + } + + b = cs->in->buf; + b->pos = b->last = b->start; + + } else { + cl = ngx_alloc_chain_link(cc->pool); + if (cl == NULL) { + ngx_rtmp_netcall_close(cc); + return; + } + + cl->next = NULL; + + cl->buf = ngx_create_temp_buf(cc->pool, cs->bufsize); + if (cl->buf == NULL) { + ngx_rtmp_netcall_close(cc); + return; + } + + if (cs->in == NULL) { + cs->in = cl; + } else { + cs->inlast->next = cl; + } + + cs->inlast = cl; + } + } + + b = cs->inlast->buf; + + n = cc->recv(cc, b->last, b->end - b->last); + + if (n == NGX_ERROR || n == 0) { + ngx_rtmp_netcall_close(cc); + return; + } + + if (n == NGX_AGAIN) { + if (cs->filter && cs->in + && cs->filter(cs->in) != NGX_AGAIN) + { + ngx_rtmp_netcall_close(cc); + return; + } + + ngx_add_timer(rev, cs->timeout); + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_rtmp_netcall_close(cc); + } + return; + } + + b->last += n; + } +} + + +static void +ngx_rtmp_netcall_send(ngx_event_t *wev) +{ + ngx_rtmp_netcall_session_t *cs; + ngx_connection_t *cc; + ngx_chain_t *cl; + + cc = wev->data; + cs = cc->data; + + if (cc->destroyed) { + return; + } + + if (wev->timedout) { + ngx_log_error(NGX_LOG_INFO, cc->log, NGX_ETIMEDOUT, + "netcall: client send timed out"); + cc->timedout = 1; + ngx_rtmp_netcall_close(cc); + return; + } + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + cl = cc->send_chain(cc, cs->out, 0); + + if (cl == NGX_CHAIN_ERROR) { + ngx_rtmp_netcall_close(cc); + return; + } + + cs->out = cl; + + /* more data to send? */ + if (cl) { + ngx_add_timer(wev, cs->timeout); + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + ngx_rtmp_netcall_close(cc); + } + return; + } + + /* we've sent everything we had. + * now receive reply */ + ngx_del_event(wev, NGX_WRITE_EVENT, 0); + + ngx_rtmp_netcall_recv(cc->read); +} + + +ngx_chain_t * +ngx_rtmp_netcall_http_format_request(ngx_int_t method, ngx_str_t *host, + ngx_str_t *uri, ngx_chain_t *args, + ngx_chain_t *body, ngx_pool_t *pool, + ngx_str_t *content_type) +{ + ngx_chain_t *al, *bl, *ret; + ngx_buf_t *b; + size_t content_length; + static const char *methods[2] = { "GET", "POST" }; + static const char rq_tmpl[] = " HTTP/1.0\r\n" + "Host: %V\r\n" + "Content-Type: %V\r\n" + "Connection: Close\r\n" + "Content-Length: %uz\r\n" + "\r\n"; + + content_length = 0; + for (al = body; al; al = al->next) { + b = al->buf; + content_length += (b->last - b->pos); + } + + /* create first buffer */ + + al = ngx_alloc_chain_link(pool); + if (al == NULL) { + return NULL; + } + + b = ngx_create_temp_buf(pool, sizeof("POST") + /* longest method + 1 */ + uri->len); + if (b == NULL) { + return NULL; + } + + b->last = ngx_snprintf(b->last, b->end - b->last, "%s %V", + methods[method], uri); + + al->buf = b; + + ret = al; + + if (args) { + *b->last++ = '?'; + al->next = args; + for (al = args; al->next; al = al->next); + } + + /* create second buffer */ + + bl = ngx_alloc_chain_link(pool); + if (bl == NULL) { + return NULL; + } + + b = ngx_create_temp_buf(pool, sizeof(rq_tmpl) + host->len + + content_type->len + NGX_SIZE_T_LEN); + if (b == NULL) { + return NULL; + } + + bl->buf = b; + + b->last = ngx_snprintf(b->last, b->end - b->last, rq_tmpl, + host, content_type, content_length); + + al->next = bl; + bl->next = body; + + return ret; +} + + +ngx_chain_t * +ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, ngx_pool_t *pool) +{ + ngx_chain_t *cl; + ngx_buf_t *b; + ngx_str_t *addr_text; + + addr_text = &s->connection->addr_text; + + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { + return NULL; + } + + b = ngx_create_temp_buf(pool, + sizeof("app=") - 1 + s->app.len * 3 + + sizeof("&flashver=") - 1 + s->flashver.len * 3 + + sizeof("&swfurl=") - 1 + s->swf_url.len * 3 + + sizeof("&tcurl=") - 1 + s->tc_url.len * 3 + + sizeof("&pageurl=") - 1 + s->page_url.len * 3 + + sizeof("&addr=") - 1 + addr_text->len * 3 + + sizeof("&clientid=") - 1 + NGX_INT_T_LEN + ); + + if (b == NULL) { + return NULL; + } + + cl->buf = b; + cl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "app=", sizeof("app=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&flashver=", + sizeof("&flashver=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->flashver.data, + s->flashver.len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&swfurl=", + sizeof("&swfurl=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->swf_url.data, + s->swf_url.len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&tcurl=", + sizeof("&tcurl=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->tc_url.data, + s->tc_url.len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&pageurl=", + sizeof("&pageurl=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->page_url.data, + s->page_url.len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&addr=", sizeof("&addr=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, addr_text->data, + addr_text->len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&clientid=", + sizeof("&clientid=") - 1); + b->last = ngx_sprintf(b->last, "%ui", (ngx_uint_t) s->connection->number); + + return cl; +} + + +ngx_chain_t * +ngx_rtmp_netcall_http_skip_header(ngx_chain_t *in) +{ + ngx_buf_t *b; + + /* find \n[\r]\n */ + enum { + normal, + lf, + lfcr + } state = normal; + + if (in == NULL) { + return NULL; + } + + b = in->buf; + + for ( ;; ) { + + while (b->pos == b->last) { + in = in->next; + if (in == NULL) { + return NULL; + } + b = in->buf; + } + + switch (*b->pos++) { + case '\r': + state = (state == lf) ? lfcr : normal; + break; + + case '\n': + if (state != normal) { + return in; + } + state = lf; + break; + + default: + state = normal; + } + } +} + + +ngx_chain_t * +ngx_rtmp_netcall_memcache_set(ngx_rtmp_session_t *s, ngx_pool_t *pool, + ngx_str_t *key, ngx_str_t *value, ngx_uint_t flags, ngx_uint_t sec) +{ + ngx_chain_t *cl; + ngx_buf_t *b; + + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { + return NULL; + } + + b = ngx_create_temp_buf(pool, sizeof("set ") - 1 + key->len + + (1 + NGX_INT_T_LEN) * 3 + + (sizeof("\r\n") - 1) * 2 + value->len); + + if (b == NULL) { + return NULL; + } + + cl->next = NULL; + cl->buf = b; + + b->last = ngx_sprintf(b->pos, "set %V %ui %ui %ui\r\n%V\r\n", + key, flags, sec, (ngx_uint_t) value->len, value); + + return cl; +} + + +static ngx_int_t +ngx_rtmp_netcall_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_DISCONNECT]); + *h = ngx_rtmp_netcall_disconnect; + + return NGX_OK; +} + diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h new file mode 100644 index 0000000..4dfa6c0 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h @@ -0,0 +1,67 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_NETCALL_H_INCLUDED_ +#define _NGX_RTMP_NETCALL_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +typedef ngx_chain_t * (*ngx_rtmp_netcall_create_pt)(ngx_rtmp_session_t *s, + void *arg, ngx_pool_t *pool); +typedef ngx_int_t (*ngx_rtmp_netcall_filter_pt)(ngx_chain_t *in); +typedef ngx_int_t (*ngx_rtmp_netcall_sink_pt)(ngx_rtmp_session_t *s, + ngx_chain_t *in); +typedef ngx_int_t (*ngx_rtmp_netcall_handle_pt)(ngx_rtmp_session_t *s, + void *arg, ngx_chain_t *in); + +#define NGX_RTMP_NETCALL_HTTP_GET 0 +#define NGX_RTMP_NETCALL_HTTP_POST 1 + + +/* If handle is NULL then netcall is created detached + * which means it's completely independent of RTMP + * session and its result is never visible to anyone. + * + * WARNING: It's not recommended to create non-detached + * netcalls from disconect handlers. Netcall disconnect + * handler which detaches active netcalls is executed + * BEFORE your handler. It leads to a crash + * after netcall connection is closed */ +typedef struct { + ngx_url_t *url; + ngx_rtmp_netcall_create_pt create; + ngx_rtmp_netcall_filter_pt filter; + ngx_rtmp_netcall_sink_pt sink; + ngx_rtmp_netcall_handle_pt handle; + void *arg; + size_t argsize; +} ngx_rtmp_netcall_init_t; + + +ngx_int_t ngx_rtmp_netcall_create(ngx_rtmp_session_t *s, + ngx_rtmp_netcall_init_t *ci); + + +/* HTTP handling */ +ngx_chain_t * ngx_rtmp_netcall_http_format_session(ngx_rtmp_session_t *s, + ngx_pool_t *pool); +ngx_chain_t * ngx_rtmp_netcall_http_format_request(ngx_int_t method, + ngx_str_t *host, ngx_str_t *uri, ngx_chain_t *args, ngx_chain_t *body, + ngx_pool_t *pool, ngx_str_t *content_type); +ngx_chain_t * ngx_rtmp_netcall_http_skip_header(ngx_chain_t *in); + + +/* Memcache handling */ +ngx_chain_t * ngx_rtmp_netcall_memcache_set(ngx_rtmp_session_t *s, + ngx_pool_t *pool, ngx_str_t *key, ngx_str_t *value, + ngx_uint_t flags, ngx_uint_t sec); + + +#endif /* _NGX_RTMP_NETCALL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c new file mode 100644 index 0000000..2fcfffb --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c @@ -0,0 +1,1728 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_netcall_module.h" +#include "ngx_rtmp_record_module.h" +#include "ngx_rtmp_relay_module.h" + + +static ngx_rtmp_connect_pt next_connect; +static ngx_rtmp_disconnect_pt next_disconnect; +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_play_pt next_play; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_record_done_pt next_record_done; + + +static char *ngx_rtmp_notify_on_srv_event(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_rtmp_notify_on_app_event(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_rtmp_notify_method(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_notify_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_notify_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static void *ngx_rtmp_notify_create_srv_conf(ngx_conf_t *cf); +static char *ngx_rtmp_notify_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_rtmp_notify_done(ngx_rtmp_session_t *s, char *cbname, + ngx_uint_t url_idx); + + +ngx_str_t ngx_rtmp_notify_urlencoded = + ngx_string("application/x-www-form-urlencoded"); + + +#define NGX_RTMP_NOTIFY_PUBLISHING 0x01 +#define NGX_RTMP_NOTIFY_PLAYING 0x02 + + +enum { + NGX_RTMP_NOTIFY_PLAY, + NGX_RTMP_NOTIFY_PUBLISH, + NGX_RTMP_NOTIFY_PLAY_DONE, + NGX_RTMP_NOTIFY_PUBLISH_DONE, + NGX_RTMP_NOTIFY_DONE, + NGX_RTMP_NOTIFY_RECORD_DONE, + NGX_RTMP_NOTIFY_UPDATE, + NGX_RTMP_NOTIFY_APP_MAX +}; + + +enum { + NGX_RTMP_NOTIFY_CONNECT, + NGX_RTMP_NOTIFY_DISCONNECT, + NGX_RTMP_NOTIFY_SRV_MAX +}; + + +typedef struct { + ngx_url_t *url[NGX_RTMP_NOTIFY_APP_MAX]; + ngx_flag_t active; + ngx_uint_t method; + ngx_msec_t update_timeout; + ngx_flag_t update_strict; + ngx_flag_t relay_redirect; +} ngx_rtmp_notify_app_conf_t; + + +typedef struct { + ngx_url_t *url[NGX_RTMP_NOTIFY_SRV_MAX]; + ngx_uint_t method; +} ngx_rtmp_notify_srv_conf_t; + + +typedef struct { + ngx_uint_t flags; + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; + ngx_event_t update_evt; + time_t start; +} ngx_rtmp_notify_ctx_t; + + +typedef struct { + u_char *cbname; + ngx_uint_t url_idx; +} ngx_rtmp_notify_done_t; + + +static ngx_command_t ngx_rtmp_notify_commands[] = { + + { ngx_string("on_connect"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_srv_event, + NGX_RTMP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_disconnect"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_srv_event, + NGX_RTMP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_publish"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_play"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_publish_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_play_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_record_done"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_RTMP_REC_CONF| + NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("on_update"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_on_app_event, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("notify_method"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_rtmp_notify_method, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("notify_update_timeout"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_notify_app_conf_t, update_timeout), + NULL }, + + { ngx_string("notify_update_strict"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_notify_app_conf_t, update_strict), + NULL }, + + { ngx_string("notify_relay_redirect"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_notify_app_conf_t, relay_redirect), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_notify_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_notify_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + ngx_rtmp_notify_create_srv_conf, /* create server configuration */ + ngx_rtmp_notify_merge_srv_conf, /* merge server configuration */ + ngx_rtmp_notify_create_app_conf, /* create app configuration */ + ngx_rtmp_notify_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_notify_module = { + NGX_MODULE_V1, + &ngx_rtmp_notify_module_ctx, /* module context */ + ngx_rtmp_notify_commands, /* module directives */ + NGX_RTMP_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_rtmp_notify_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_notify_app_conf_t *nacf; + ngx_uint_t n; + + nacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_notify_app_conf_t)); + if (nacf == NULL) { + return NULL; + } + + for (n = 0; n < NGX_RTMP_NOTIFY_APP_MAX; ++n) { + nacf->url[n] = NGX_CONF_UNSET_PTR; + } + + nacf->method = NGX_CONF_UNSET_UINT; + nacf->update_timeout = NGX_CONF_UNSET_MSEC; + nacf->update_strict = NGX_CONF_UNSET; + nacf->relay_redirect = NGX_CONF_UNSET; + + return nacf; +} + + +static char * +ngx_rtmp_notify_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_notify_app_conf_t *prev = parent; + ngx_rtmp_notify_app_conf_t *conf = child; + ngx_uint_t n; + + for (n = 0; n < NGX_RTMP_NOTIFY_APP_MAX; ++n) { + ngx_conf_merge_ptr_value(conf->url[n], prev->url[n], NULL); + if (conf->url[n]) { + conf->active = 1; + } + } + + if (conf->active) { + prev->active = 1; + } + + ngx_conf_merge_uint_value(conf->method, prev->method, + NGX_RTMP_NETCALL_HTTP_POST); + ngx_conf_merge_msec_value(conf->update_timeout, prev->update_timeout, + 30000); + ngx_conf_merge_value(conf->update_strict, prev->update_strict, 0); + ngx_conf_merge_value(conf->relay_redirect, prev->relay_redirect, 0); + + return NGX_CONF_OK; +} + + +static void * +ngx_rtmp_notify_create_srv_conf(ngx_conf_t *cf) +{ + ngx_rtmp_notify_srv_conf_t *nscf; + ngx_uint_t n; + + nscf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_notify_srv_conf_t)); + if (nscf == NULL) { + return NULL; + } + + for (n = 0; n < NGX_RTMP_NOTIFY_SRV_MAX; ++n) { + nscf->url[n] = NGX_CONF_UNSET_PTR; + } + + nscf->method = NGX_CONF_UNSET_UINT; + + return nscf; +} + + +static char * +ngx_rtmp_notify_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_notify_srv_conf_t *prev = parent; + ngx_rtmp_notify_srv_conf_t *conf = child; + ngx_uint_t n; + + for (n = 0; n < NGX_RTMP_NOTIFY_SRV_MAX; ++n) { + ngx_conf_merge_ptr_value(conf->url[n], prev->url[n], NULL); + } + + ngx_conf_merge_uint_value(conf->method, prev->method, + NGX_RTMP_NETCALL_HTTP_POST); + + return NGX_CONF_OK; +} + + +static ngx_chain_t * +ngx_rtmp_notify_create_request(ngx_rtmp_session_t *s, ngx_pool_t *pool, + ngx_uint_t url_idx, ngx_chain_t *args) +{ + ngx_rtmp_notify_app_conf_t *nacf; + ngx_chain_t *al, *bl, *cl; + ngx_url_t *url; + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + + url = nacf->url[url_idx]; + + al = ngx_rtmp_netcall_http_format_session(s, pool); + if (al == NULL) { + return NULL; + } + + al->next = args; + + bl = NULL; + + if (nacf->method == NGX_RTMP_NETCALL_HTTP_POST) { + cl = al; + al = bl; + bl = cl; + } + + return ngx_rtmp_netcall_http_format_request(nacf->method, &url->host, + &url->uri, al, bl, pool, + &ngx_rtmp_notify_urlencoded); +} + + +static ngx_chain_t * +ngx_rtmp_notify_connect_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_connect_t *v = arg; + + ngx_rtmp_notify_srv_conf_t *nscf; + ngx_url_t *url; + ngx_chain_t *al, *bl; + ngx_buf_t *b; + ngx_str_t *addr_text; + size_t app_len, args_len, flashver_len, + swf_url_len, tc_url_len, page_url_len; + + nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module); + + al = ngx_alloc_chain_link(pool); + if (al == NULL) { + return NULL; + } + + /* these values are still missing in session + * so we have to construct the request from + * connection struct */ + + app_len = ngx_strlen(v->app); + args_len = ngx_strlen(v->args); + flashver_len = ngx_strlen(v->flashver); + swf_url_len = ngx_strlen(v->swf_url); + tc_url_len = ngx_strlen(v->tc_url); + page_url_len = ngx_strlen(v->page_url); + + addr_text = &s->connection->addr_text; + + b = ngx_create_temp_buf(pool, + sizeof("call=connect") - 1 + + sizeof("&app=") - 1 + app_len * 3 + + sizeof("&flashver=") - 1 + flashver_len * 3 + + sizeof("&swfurl=") - 1 + swf_url_len * 3 + + sizeof("&tcurl=") - 1 + tc_url_len * 3 + + sizeof("&pageurl=") - 1 + page_url_len * 3 + + sizeof("&addr=") - 1 + addr_text->len * 3 + + sizeof("&epoch=") - 1 + NGX_INT32_LEN + + 1 + args_len + ); + + if (b == NULL) { + return NULL; + } + + al->buf = b; + al->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "app=", sizeof("app=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->app, app_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&flashver=", + sizeof("&flashver=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->flashver, flashver_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&swfurl=", + sizeof("&swfurl=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->swf_url, swf_url_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&tcurl=", + sizeof("&tcurl=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->tc_url, tc_url_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&pageurl=", + sizeof("&pageurl=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->page_url, page_url_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&addr=", sizeof("&addr=") -1); + b->last = (u_char*) ngx_escape_uri(b->last, addr_text->data, + addr_text->len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&epoch=", sizeof("&epoch=") -1); + b->last = ngx_sprintf(b->last, "%uD", (uint32_t) s->epoch); + + b->last = ngx_cpymem(b->last, (u_char*) "&call=connect", + sizeof("&call=connect") - 1); + + if (args_len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len); + } + + url = nscf->url[NGX_RTMP_NOTIFY_CONNECT]; + + bl = NULL; + + if (nscf->method == NGX_RTMP_NETCALL_HTTP_POST) { + bl = al; + al = NULL; + } + + return ngx_rtmp_netcall_http_format_request(nscf->method, &url->host, + &url->uri, al, bl, pool, + &ngx_rtmp_notify_urlencoded); +} + + +static ngx_chain_t * +ngx_rtmp_notify_disconnect_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_notify_srv_conf_t *nscf; + ngx_url_t *url; + ngx_chain_t *al, *bl, *pl; + ngx_buf_t *b; + + nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module); + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + b = ngx_create_temp_buf(pool, + sizeof("&call=disconnect") + + sizeof("&app=") + s->app.len * 3 + + 1 + s->args.len); + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=disconnect", + sizeof("&call=disconnect") - 1); + + b->last = ngx_cpymem(b->last, (u_char*) "&app=", sizeof("&app=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, s->app.data, s->app.len, + NGX_ESCAPE_ARGS); + + if (s->args.len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, s->args.data, s->args.len); + } + + url = nscf->url[NGX_RTMP_NOTIFY_DISCONNECT]; + + al = ngx_rtmp_netcall_http_format_session(s, pool); + if (al == NULL) { + return NULL; + } + + al->next = pl; + + bl = NULL; + + if (nscf->method == NGX_RTMP_NETCALL_HTTP_POST) { + bl = al; + al = NULL; + } + + return ngx_rtmp_netcall_http_format_request(nscf->method, &url->host, + &url->uri, al, bl, pool, + &ngx_rtmp_notify_urlencoded); +} + + +static ngx_chain_t * +ngx_rtmp_notify_publish_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_publish_t *v = arg; + + ngx_chain_t *pl; + ngx_buf_t *b; + size_t name_len, type_len, args_len; + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + name_len = ngx_strlen(v->name); + type_len = ngx_strlen(v->type); + args_len = ngx_strlen(v->args); + + b = ngx_create_temp_buf(pool, + sizeof("&call=publish") + + sizeof("&name=") + name_len * 3 + + sizeof("&type=") + type_len * 3 + + 1 + args_len); + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=publish", + sizeof("&call=publish") - 1); + + b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->name, name_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&type=", sizeof("&type=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->type, type_len, + NGX_ESCAPE_ARGS); + + if (args_len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len); + } + + return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_PUBLISH, pl); +} + + +static ngx_chain_t * +ngx_rtmp_notify_play_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_play_t *v = arg; + + ngx_chain_t *pl; + ngx_buf_t *b; + size_t name_len, args_len; + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + name_len = ngx_strlen(v->name); + args_len = ngx_strlen(v->args); + + b = ngx_create_temp_buf(pool, + sizeof("&call=play") + + sizeof("&name=") + name_len * 3 + + sizeof("&start=&duration=&reset=") + + NGX_INT32_LEN * 3 + 1 + args_len); + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=play", + sizeof("&call=play") - 1); + + b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->name, name_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_snprintf(b->last, b->end - b->last, + "&start=%uD&duration=%uD&reset=%d", + (uint32_t) v->start, (uint32_t) v->duration, + v->reset & 1); + + if (args_len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, v->args, args_len); + } + + return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_PLAY, pl); +} + + +static ngx_chain_t * +ngx_rtmp_notify_done_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_notify_done_t *ds = arg; + + ngx_chain_t *pl; + ngx_buf_t *b; + size_t cbname_len, name_len, args_len; + ngx_rtmp_notify_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + cbname_len = ngx_strlen(ds->cbname); + name_len = ctx ? ngx_strlen(ctx->name) : 0; + args_len = ctx ? ngx_strlen(ctx->args) : 0; + + b = ngx_create_temp_buf(pool, + sizeof("&call=") + cbname_len + + sizeof("&name=") + name_len * 3 + + 1 + args_len); + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=", sizeof("&call=") - 1); + b->last = ngx_cpymem(b->last, ds->cbname, cbname_len); + + if (name_len) { + b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len, + NGX_ESCAPE_ARGS); + } + + if (args_len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); + } + + return ngx_rtmp_notify_create_request(s, pool, ds->url_idx, pl); +} + + +static ngx_chain_t * +ngx_rtmp_notify_update_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_chain_t *pl; + ngx_buf_t *b; + size_t name_len, args_len; + ngx_rtmp_notify_ctx_t *ctx; + ngx_str_t sfx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + if (ctx->flags & NGX_RTMP_NOTIFY_PUBLISHING) { + ngx_str_set(&sfx, "_publish"); + } else if (ctx->flags & NGX_RTMP_NOTIFY_PLAYING) { + ngx_str_set(&sfx, "_play"); + } else { + ngx_str_null(&sfx); + } + + name_len = ctx ? ngx_strlen(ctx->name) : 0; + args_len = ctx ? ngx_strlen(ctx->args) : 0; + + b = ngx_create_temp_buf(pool, + sizeof("&call=update") + sfx.len + + sizeof("&time=") + NGX_TIME_T_LEN + + sizeof("×tamp=") + NGX_INT32_LEN + + sizeof("&name=") + name_len * 3 + + 1 + args_len); + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=update", + sizeof("&call=update") - 1); + b->last = ngx_cpymem(b->last, sfx.data, sfx.len); + + b->last = ngx_cpymem(b->last, (u_char *) "&time=", + sizeof("&time=") - 1); + b->last = ngx_sprintf(b->last, "%T", ngx_cached_time->sec - ctx->start); + + b->last = ngx_cpymem(b->last, (u_char *) "×tamp=", + sizeof("×tamp=") - 1); + b->last = ngx_sprintf(b->last, "%D", s->current_time); + + if (name_len) { + b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len, + NGX_ESCAPE_ARGS); + } + + if (args_len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); + } + + return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_UPDATE, pl); +} + + +static ngx_chain_t * +ngx_rtmp_notify_record_done_create(ngx_rtmp_session_t *s, void *arg, + ngx_pool_t *pool) +{ + ngx_rtmp_record_done_t *v = arg; + + ngx_rtmp_notify_ctx_t *ctx; + ngx_chain_t *pl; + ngx_buf_t *b; + size_t name_len, args_len; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + pl = ngx_alloc_chain_link(pool); + if (pl == NULL) { + return NULL; + } + + name_len = ngx_strlen(ctx->name); + args_len = ngx_strlen(ctx->args); + + b = ngx_create_temp_buf(pool, + sizeof("&call=record_done") + + sizeof("&recorder=") + v->recorder.len + + sizeof("&name=") + name_len * 3 + + sizeof("&path=") + v->path.len * 3 + + 1 + args_len); + if (b == NULL) { + return NULL; + } + + pl->buf = b; + pl->next = NULL; + + b->last = ngx_cpymem(b->last, (u_char*) "&call=record_done", + sizeof("&call=record_done") - 1); + + b->last = ngx_cpymem(b->last, (u_char *) "&recorder=", + sizeof("&recorder=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->recorder.data, + v->recorder.len, NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&name=", sizeof("&name=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, ctx->name, name_len, + NGX_ESCAPE_ARGS); + + b->last = ngx_cpymem(b->last, (u_char*) "&path=", sizeof("&path=") - 1); + b->last = (u_char*) ngx_escape_uri(b->last, v->path.data, v->path.len, + NGX_ESCAPE_ARGS); + + if (args_len) { + *b->last++ = '&'; + b->last = (u_char *) ngx_cpymem(b->last, ctx->args, args_len); + } + + return ngx_rtmp_notify_create_request(s, pool, NGX_RTMP_NOTIFY_RECORD_DONE, + pl); +} + + +static ngx_int_t +ngx_rtmp_notify_parse_http_retcode(ngx_rtmp_session_t *s, + ngx_chain_t *in) +{ + ngx_buf_t *b; + ngx_int_t n; + u_char c; + + /* find 10th character */ + + n = 9; + while (in) { + b = in->buf; + if (b->last - b->pos > n) { + c = b->pos[n]; + if (c >= (u_char)'0' && c <= (u_char)'9') { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "notify: HTTP retcode: %dxx", (int)(c - '0')); + switch (c) { + case (u_char) '2': + return NGX_OK; + case (u_char) '3': + return NGX_AGAIN; + default: + return NGX_ERROR; + } + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: invalid HTTP retcode: %d..", (int)c); + + return NGX_ERROR; + } + n -= (b->last - b->pos); + in = in->next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: empty or broken HTTP response"); + + /* + * not enough data; + * it can happen in case of empty or broken reply + */ + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_rtmp_notify_parse_http_header(ngx_rtmp_session_t *s, + ngx_chain_t *in, ngx_str_t *name, u_char *data, size_t len) +{ + ngx_buf_t *b; + ngx_int_t matched; + u_char *p, c; + ngx_uint_t n; + + enum { + parse_name, + parse_space, + parse_value, + parse_value_newline + } state = parse_name; + + n = 0; + matched = 0; + + while (in) { + b = in->buf; + + for (p = b->pos; p != b->last; ++p) { + c = *p; + + if (c == '\r') { + continue; + } + + switch (state) { + case parse_value_newline: + if (c == ' ' || c == '\t') { + state = parse_space; + break; + } + + if (matched) { + return n; + } + + if (c == '\n') { + return NGX_OK; + } + + n = 0; + state = parse_name; + + case parse_name: + switch (c) { + case ':': + matched = (n == name->len); + n = 0; + state = parse_space; + break; + case '\n': + n = 0; + break; + default: + if (n < name->len && + ngx_tolower(c) == ngx_tolower(name->data[n])) + { + ++n; + break; + } + n = name->len + 1; + } + break; + + case parse_space: + if (c == ' ' || c == '\t') { + break; + } + state = parse_value; + + case parse_value: + if (c == '\n') { + state = parse_value_newline; + break; + } + + if (matched && n + 1 < len) { + data[n++] = c; + } + + break; + } + } + + in = in->next; + } + + return NGX_OK; +} + + +static void +ngx_rtmp_notify_clear_flag(ngx_rtmp_session_t *s, ngx_uint_t flag) +{ + ngx_rtmp_notify_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + ctx->flags &= ~flag; +} + + +static ngx_int_t +ngx_rtmp_notify_connect_handle(ngx_rtmp_session_t *s, + void *arg, ngx_chain_t *in) +{ + ngx_rtmp_connect_t *v = arg; + ngx_int_t rc; + u_char app[NGX_RTMP_MAX_NAME]; + + static ngx_str_t location = ngx_string("location"); + + rc = ngx_rtmp_notify_parse_http_retcode(s, in); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_AGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "notify: connect redirect received"); + + rc = ngx_rtmp_notify_parse_http_header(s, in, &location, app, + sizeof(app) - 1); + if (rc > 0) { + *ngx_cpymem(v->app, app, rc) = 0; + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: connect redirect to '%s'", v->app); + } + } + + return next_connect(s, v); +} + + +static void +ngx_rtmp_notify_set_name(u_char *dst, size_t dst_len, u_char *src, + size_t src_len) +{ + u_char result[16], *p; + ngx_md5_t md5; + + ngx_md5_init(&md5); + ngx_md5_update(&md5, src, src_len); + ngx_md5_final(result, &md5); + + p = ngx_hex_dump(dst, result, ngx_min((dst_len - 1) / 2, 16)); + *p = '\0'; +} + + +static ngx_int_t +ngx_rtmp_notify_publish_handle(ngx_rtmp_session_t *s, + void *arg, ngx_chain_t *in) +{ + ngx_rtmp_publish_t *v = arg; + ngx_int_t rc; + ngx_str_t local_name; + ngx_rtmp_relay_target_t target; + ngx_url_t *u; + ngx_rtmp_notify_app_conf_t *nacf; + u_char name[NGX_RTMP_MAX_NAME]; + + static ngx_str_t location = ngx_string("location"); + + rc = ngx_rtmp_notify_parse_http_retcode(s, in); + if (rc == NGX_ERROR) { + ngx_rtmp_notify_clear_flag(s, NGX_RTMP_NOTIFY_PUBLISHING); + return NGX_ERROR; + } + + if (rc != NGX_AGAIN) { + goto next; + } + + /* HTTP 3xx */ + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "notify: publish redirect received"); + + rc = ngx_rtmp_notify_parse_http_header(s, in, &location, name, + sizeof(name) - 1); + if (rc <= 0) { + goto next; + } + + if (ngx_strncasecmp(name, (u_char *) "rtmp://", 7)) { + *ngx_cpymem(v->name, name, rc) = 0; + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: publish redirect to '%s'", v->name); + goto next; + } + + /* push */ + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (nacf->relay_redirect) { + ngx_rtmp_notify_set_name(v->name, NGX_RTMP_MAX_NAME, name, (size_t) rc); + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "notify: push '%s' to '%*s'", v->name, rc, name); + + local_name.data = v->name; + local_name.len = ngx_strlen(v->name); + + ngx_memzero(&target, sizeof(target)); + + u = &target.url; + u->url = local_name; + u->url.data = name + 7; + u->url.len = rc - 7; + u->default_port = 1935; + u->uri_part = 1; + u->no_resolve = 1; /* want ip here */ + + if (ngx_parse_url(s->connection->pool, u) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: push failed '%V'", &local_name); + return NGX_ERROR; + } + + ngx_rtmp_relay_push(s, &local_name, &target); + +next: + + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_play_handle(ngx_rtmp_session_t *s, + void *arg, ngx_chain_t *in) +{ + ngx_rtmp_play_t *v = arg; + ngx_int_t rc; + ngx_str_t local_name; + ngx_rtmp_relay_target_t target; + ngx_url_t *u; + ngx_rtmp_notify_app_conf_t *nacf; + u_char name[NGX_RTMP_MAX_NAME]; + + static ngx_str_t location = ngx_string("location"); + + rc = ngx_rtmp_notify_parse_http_retcode(s, in); + if (rc == NGX_ERROR) { + ngx_rtmp_notify_clear_flag(s, NGX_RTMP_NOTIFY_PLAYING); + return NGX_ERROR; + } + + if (rc != NGX_AGAIN) { + goto next; + } + + /* HTTP 3xx */ + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "notify: play redirect received"); + + rc = ngx_rtmp_notify_parse_http_header(s, in, &location, name, + sizeof(name) - 1); + if (rc <= 0) { + goto next; + } + + if (ngx_strncasecmp(name, (u_char *) "rtmp://", 7)) { + *ngx_cpymem(v->name, name, rc) = 0; + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: play redirect to '%s'", v->name); + goto next; + } + + /* pull */ + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (nacf->relay_redirect) { + ngx_rtmp_notify_set_name(v->name, NGX_RTMP_MAX_NAME, name, (size_t) rc); + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: pull '%s' from '%*s'", v->name, rc, name); + + local_name.data = v->name; + local_name.len = ngx_strlen(v->name); + + ngx_memzero(&target, sizeof(target)); + + u = &target.url; + u->url = local_name; + u->url.data = name + 7; + u->url.len = rc - 7; + u->default_port = 1935; + u->uri_part = 1; + u->no_resolve = 1; /* want ip here */ + + if (ngx_parse_url(s->connection->pool, u) != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: pull failed '%V'", &local_name); + return NGX_ERROR; + } + + ngx_rtmp_relay_pull(s, &local_name, &target); + +next: + + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_update_handle(ngx_rtmp_session_t *s, + void *arg, ngx_chain_t *in) +{ + ngx_rtmp_notify_app_conf_t *nacf; + ngx_rtmp_notify_ctx_t *ctx; + ngx_int_t rc; + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + + rc = ngx_rtmp_notify_parse_http_retcode(s, in); + + if ((!nacf->update_strict && rc == NGX_ERROR) || + (nacf->update_strict && rc != NGX_OK)) + { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: update failed"); + + return NGX_ERROR; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "notify: schedule update %Mms", + nacf->update_timeout); + + ngx_add_timer(&ctx->update_evt, nacf->update_timeout); + + return NGX_OK; +} + + +static void +ngx_rtmp_notify_update(ngx_event_t *e) +{ + ngx_connection_t *c; + ngx_rtmp_session_t *s; + ngx_rtmp_notify_app_conf_t *nacf; + ngx_rtmp_netcall_init_t ci; + ngx_url_t *url; + + c = e->data; + s = c->data; + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + + url = nacf->url[NGX_RTMP_NOTIFY_UPDATE]; + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: update '%V'", &url->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = url; + ci.create = ngx_rtmp_notify_update_create; + ci.handle = ngx_rtmp_notify_update_handle; + + if (ngx_rtmp_netcall_create(s, &ci) == NGX_OK) { + return; + } + + /* schedule next update on connection error */ + + ngx_rtmp_notify_update_handle(s, NULL, NULL); +} + + +static void +ngx_rtmp_notify_init(ngx_rtmp_session_t *s, + u_char name[NGX_RTMP_MAX_NAME], u_char args[NGX_RTMP_MAX_ARGS], + ngx_uint_t flags) +{ + ngx_rtmp_notify_ctx_t *ctx; + ngx_rtmp_notify_app_conf_t *nacf; + ngx_event_t *e; + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (!nacf->active) { + return; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_notify_ctx_t)); + if (ctx == NULL) { + return; + } + + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_notify_module); + } + + ngx_memcpy(ctx->name, name, NGX_RTMP_MAX_NAME); + ngx_memcpy(ctx->args, args, NGX_RTMP_MAX_ARGS); + + ctx->flags |= flags; + + if (nacf->url[NGX_RTMP_NOTIFY_UPDATE] == NULL || + nacf->update_timeout == 0) + { + return; + } + + if (ctx->update_evt.timer_set) { + return; + } + + ctx->start = ngx_cached_time->sec; + + e = &ctx->update_evt; + + e->data = s->connection; + e->log = s->connection->log; + e->handler = ngx_rtmp_notify_update; + + ngx_add_timer(e, nacf->update_timeout); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "notify: schedule initial update %Mms", + nacf->update_timeout); +} + + +static ngx_int_t +ngx_rtmp_notify_connect(ngx_rtmp_session_t *s, ngx_rtmp_connect_t *v) +{ + ngx_rtmp_notify_srv_conf_t *nscf; + ngx_rtmp_netcall_init_t ci; + ngx_url_t *url; + + if (s->auto_pushed || s->relay) { + goto next; + } + + nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module); + + url = nscf->url[NGX_RTMP_NOTIFY_CONNECT]; + if (url == NULL) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: connect '%V'", &url->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = url; + ci.create = ngx_rtmp_notify_connect_create; + ci.handle = ngx_rtmp_notify_connect_handle; + ci.arg = v; + ci.argsize = sizeof(*v); + + return ngx_rtmp_netcall_create(s, &ci); + +next: + return next_connect(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_disconnect(ngx_rtmp_session_t *s) +{ + ngx_rtmp_notify_srv_conf_t *nscf; + ngx_rtmp_netcall_init_t ci; + ngx_url_t *url; + + if (s->auto_pushed || s->relay) { + goto next; + } + + nscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_notify_module); + + url = nscf->url[NGX_RTMP_NOTIFY_DISCONNECT]; + if (url == NULL) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: disconnect '%V'", &url->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = url; + ci.create = ngx_rtmp_notify_disconnect_create; + + ngx_rtmp_netcall_create(s, &ci); + +next: + return next_disconnect(s); +} + + +static ngx_int_t +ngx_rtmp_notify_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_notify_app_conf_t *nacf; + ngx_rtmp_netcall_init_t ci; + ngx_url_t *url; + + if (s->auto_pushed) { + goto next; + } + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (nacf == NULL) { + goto next; + } + + url = nacf->url[NGX_RTMP_NOTIFY_PUBLISH]; + + ngx_rtmp_notify_init(s, v->name, v->args, NGX_RTMP_NOTIFY_PUBLISHING); + + if (url == NULL) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: publish '%V'", &url->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = url; + ci.create = ngx_rtmp_notify_publish_create; + ci.handle = ngx_rtmp_notify_publish_handle; + ci.arg = v; + ci.argsize = sizeof(*v); + + return ngx_rtmp_netcall_create(s, &ci); + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_notify_app_conf_t *nacf; + ngx_rtmp_netcall_init_t ci; + ngx_url_t *url; + + if (s->auto_pushed) { + goto next; + } + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (nacf == NULL) { + goto next; + } + + url = nacf->url[NGX_RTMP_NOTIFY_PLAY]; + + ngx_rtmp_notify_init(s, v->name, v->args, NGX_RTMP_NOTIFY_PLAYING); + + if (url == NULL) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: play '%V'", &url->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = url; + ci.create = ngx_rtmp_notify_play_create; + ci.handle = ngx_rtmp_notify_play_handle; + ci.arg = v; + ci.argsize = sizeof(*v); + + return ngx_rtmp_netcall_create(s, &ci); + +next: + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_close_stream(ngx_rtmp_session_t *s, + ngx_rtmp_close_stream_t *v) +{ + ngx_rtmp_notify_ctx_t *ctx; + ngx_rtmp_notify_app_conf_t *nacf; + + if (s->auto_pushed) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_notify_module); + + if (ctx == NULL) { + goto next; + } + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + + if (nacf == NULL) { + goto next; + } + + if (ctx->flags & NGX_RTMP_NOTIFY_PUBLISHING) { + ngx_rtmp_notify_done(s, "publish_done", NGX_RTMP_NOTIFY_PUBLISH_DONE); + } + + if (ctx->flags & NGX_RTMP_NOTIFY_PLAYING) { + ngx_rtmp_notify_done(s, "play_done", NGX_RTMP_NOTIFY_PLAY_DONE); + } + + if (ctx->flags) { + ngx_rtmp_notify_done(s, "done", NGX_RTMP_NOTIFY_DONE); + } + + if (ctx->update_evt.timer_set) { + ngx_del_timer(&ctx->update_evt); + } + + ctx->flags = 0; + +next: + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_record_done(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v) +{ + ngx_rtmp_netcall_init_t ci; + ngx_rtmp_notify_app_conf_t *nacf; + + if (s->auto_pushed) { + goto next; + } + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + if (nacf == NULL || nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE] == NULL) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: record_done recorder=%V path='%V' url='%V'", + &v->recorder, &v->path, + &nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE]->url); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = nacf->url[NGX_RTMP_NOTIFY_RECORD_DONE]; + ci.create = ngx_rtmp_notify_record_done_create; + ci.arg = v; + + ngx_rtmp_netcall_create(s, &ci); + +next: + return next_record_done(s, v); +} + + +static ngx_int_t +ngx_rtmp_notify_done(ngx_rtmp_session_t *s, char *cbname, ngx_uint_t url_idx) +{ + ngx_rtmp_netcall_init_t ci; + ngx_rtmp_notify_done_t ds; + ngx_rtmp_notify_app_conf_t *nacf; + ngx_url_t *url; + + nacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_notify_module); + + url = nacf->url[url_idx]; + if (url == NULL) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "notify: %s '%V'", cbname, &url->url); + + ds.cbname = (u_char *) cbname; + ds.url_idx = url_idx; + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = url; + ci.arg = &ds; + ci.create = ngx_rtmp_notify_done_create; + + return ngx_rtmp_netcall_create(s, &ci); +} + + +static ngx_url_t * +ngx_rtmp_notify_parse_url(ngx_conf_t *cf, ngx_str_t *url) +{ + ngx_url_t *u; + size_t add; + + add = 0; + + u = ngx_pcalloc(cf->pool, sizeof(ngx_url_t)); + if (u == NULL) { + return NULL; + } + + if (ngx_strncasecmp(url->data, (u_char *) "http://", 7) == 0) { + add = 7; + } + + u->url.len = url->len - add; + u->url.data = url->data + add; + u->default_port = 80; + u->uri_part = 1; + + if (ngx_parse_url(cf->pool, u) != NGX_OK) { + if (u->err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in url \"%V\"", u->err, &u->url); + } + return NULL; + } + + return u; +} + + +static char * +ngx_rtmp_notify_on_srv_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_notify_srv_conf_t *nscf = conf; + + ngx_str_t *name, *value; + ngx_url_t *u; + ngx_uint_t n; + + value = cf->args->elts; + + u = ngx_rtmp_notify_parse_url(cf, &value[1]); + if (u == NULL) { + return NGX_CONF_ERROR; + } + + name = &value[0]; + + n = 0; + + switch (name->len) { + case sizeof("on_connect") - 1: + n = NGX_RTMP_NOTIFY_CONNECT; + break; + + case sizeof("on_disconnect") - 1: + n = NGX_RTMP_NOTIFY_DISCONNECT; + break; + } + + nscf->url[n] = u; + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_notify_on_app_event(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_notify_app_conf_t *nacf = conf; + + ngx_str_t *name, *value; + ngx_url_t *u; + ngx_uint_t n; + + value = cf->args->elts; + + u = ngx_rtmp_notify_parse_url(cf, &value[1]); + if (u == NULL) { + return NGX_CONF_ERROR; + } + + name = &value[0]; + + n = 0; + + switch (name->len) { + case sizeof("on_done") - 1: /* and on_play */ + if (name->data[3] == 'd') { + n = NGX_RTMP_NOTIFY_DONE; + } else { + n = NGX_RTMP_NOTIFY_PLAY; + } + break; + + case sizeof("on_update") - 1: + n = NGX_RTMP_NOTIFY_UPDATE; + break; + + case sizeof("on_publish") - 1: + n = NGX_RTMP_NOTIFY_PUBLISH; + break; + + case sizeof("on_play_done") - 1: + n = NGX_RTMP_NOTIFY_PLAY_DONE; + break; + + case sizeof("on_record_done") - 1: + n = NGX_RTMP_NOTIFY_RECORD_DONE; + break; + + case sizeof("on_publish_done") - 1: + n = NGX_RTMP_NOTIFY_PUBLISH_DONE; + break; + } + + nacf->url[n] = u; + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_notify_method(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_notify_app_conf_t *nacf = conf; + + ngx_rtmp_notify_srv_conf_t *nscf; + ngx_str_t *value; + + value = cf->args->elts; + value++; + + if (value->len == sizeof("get") - 1 && + ngx_strncasecmp(value->data, (u_char *) "get", value->len) == 0) + { + nacf->method = NGX_RTMP_NETCALL_HTTP_GET; + + } else if (value->len == sizeof("post") - 1 && + ngx_strncasecmp(value->data, (u_char *) "post", value->len) == 0) + { + nacf->method = NGX_RTMP_NETCALL_HTTP_POST; + + } else { + return "got unexpected method"; + } + + nscf = ngx_rtmp_conf_get_module_srv_conf(cf, ngx_rtmp_notify_module); + nscf->method = nacf->method; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_notify_postconfiguration(ngx_conf_t *cf) +{ + next_connect = ngx_rtmp_connect; + ngx_rtmp_connect = ngx_rtmp_notify_connect; + + next_disconnect = ngx_rtmp_disconnect; + ngx_rtmp_disconnect = ngx_rtmp_notify_disconnect; + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_notify_publish; + + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_notify_play; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_notify_close_stream; + + next_record_done = ngx_rtmp_record_done; + ngx_rtmp_record_done = ngx_rtmp_notify_record_done; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_play_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_play_module.c new file mode 100644 index 0000000..f6ea6c3 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_play_module.c @@ -0,0 +1,1278 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include "ngx_rtmp_play_module.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_netcall_module.h" +#include "ngx_rtmp_streams.h" + + +static ngx_rtmp_play_pt next_play; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_seek_pt next_seek; +static ngx_rtmp_pause_pt next_pause; + + +static char *ngx_rtmp_play_url(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_rtmp_play_create_main_conf(ngx_conf_t *cf); +static ngx_int_t ngx_rtmp_play_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_play_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_play_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); + +static ngx_int_t ngx_rtmp_play_do_init(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_play_do_done(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_play_do_start(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_play_do_stop(ngx_rtmp_session_t *s); +static ngx_int_t ngx_rtmp_play_do_seek(ngx_rtmp_session_t *s, + ngx_uint_t timestamp); + +static ngx_int_t ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v); +static ngx_int_t ngx_rtmp_play_seek(ngx_rtmp_session_t *s, ngx_rtmp_seek_t *v); +static ngx_int_t ngx_rtmp_play_pause(ngx_rtmp_session_t *s, + ngx_rtmp_pause_t *v); +static void ngx_rtmp_play_send(ngx_event_t *e); +static ngx_int_t ngx_rtmp_play_open(ngx_rtmp_session_t *s, double start); +static ngx_int_t ngx_rtmp_play_remote_handle(ngx_rtmp_session_t *s, + void *arg, ngx_chain_t *in); +static ngx_chain_t * ngx_rtmp_play_remote_create(ngx_rtmp_session_t *s, + void *arg, ngx_pool_t *pool); +static ngx_int_t ngx_rtmp_play_open_remote(ngx_rtmp_session_t *s, + ngx_rtmp_play_t *v); +static ngx_int_t ngx_rtmp_play_next_entry(ngx_rtmp_session_t *s, + ngx_rtmp_play_t *v); +static ngx_rtmp_play_entry_t * ngx_rtmp_play_get_current_entry( + ngx_rtmp_session_t *s); +static void ngx_rtmp_play_cleanup_local_file(ngx_rtmp_session_t *s); +static void ngx_rtmp_play_copy_local_file(ngx_rtmp_session_t *s, u_char *name); +static u_char * ngx_rtmp_play_get_local_file_path(ngx_rtmp_session_t *s); + + +static ngx_command_t ngx_rtmp_play_commands[] = { + + { ngx_string("play"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_play_url, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("play_temp_path"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_play_app_conf_t, temp_path), + NULL }, + + { ngx_string("play_local_path"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_play_app_conf_t, local_path), + NULL }, + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_play_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_play_postconfiguration, /* postconfiguration */ + ngx_rtmp_play_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_play_create_app_conf, /* create app configuration */ + ngx_rtmp_play_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_play_module = { + NGX_MODULE_V1, + &ngx_rtmp_play_module_ctx, /* module context */ + ngx_rtmp_play_commands, /* module directives */ + NGX_RTMP_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 +}; + + +#define NGX_RTMP_PLAY_TMP_FILE "nginx-rtmp-vod." + + +static void * +ngx_rtmp_play_create_main_conf(ngx_conf_t *cf) +{ + ngx_rtmp_play_main_conf_t *pmcf; + + pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_play_main_conf_t)); + if (pmcf == NULL) { + return NULL; + } + + if (ngx_array_init(&pmcf->fmts, cf->pool, 1, + sizeof(ngx_rtmp_play_fmt_t *)) + != NGX_OK) + { + return NULL; + } + + return pmcf; +} + + +static void * +ngx_rtmp_play_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_play_app_conf_t *pacf; + + pacf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_play_app_conf_t)); + if (pacf == NULL) { + return NULL; + } + + pacf->nbuckets = 1024; + + return pacf; +} + + +static char * +ngx_rtmp_play_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_play_app_conf_t *prev = parent; + ngx_rtmp_play_app_conf_t *conf = child; + ngx_rtmp_play_entry_t **ppe; + + ngx_conf_merge_str_value(conf->temp_path, prev->temp_path, "/tmp"); + ngx_conf_merge_str_value(conf->local_path, prev->local_path, ""); + + if (prev->entries.nelts == 0) { + goto done; + } + + if (conf->entries.nelts == 0) { + conf->entries = prev->entries; + goto done; + } + + ppe = ngx_array_push_n(&conf->entries, prev->entries.nelts); + if (ppe == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(ppe, prev->entries.elts, prev->entries.nelts * sizeof(void *)); + +done: + + if (conf->entries.nelts == 0) { + return NGX_CONF_OK; + } + + conf->ctx = ngx_pcalloc(cf->pool, sizeof(void *) * conf->nbuckets); + if (conf->ctx == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_play_join(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx, **pctx; + ngx_rtmp_play_app_conf_t *pacf; + ngx_uint_t h; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: join"); + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + if (ctx == NULL || ctx->joined) { + return NGX_ERROR; + } + + h = ngx_hash_key(ctx->name, ngx_strlen(ctx->name)); + pctx = &pacf->ctx[h % pacf->nbuckets]; + + while (*pctx) { + if (!ngx_strncmp((*pctx)->name, ctx->name, NGX_RTMP_MAX_NAME)) { + break; + } + pctx = &(*pctx)->next; + } + + ctx->next = *pctx; + *pctx = ctx; + ctx->joined = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_play_leave(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx, **pctx; + ngx_rtmp_play_app_conf_t *pacf; + ngx_uint_t h; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: leave"); + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + if (ctx == NULL || !ctx->joined) { + return NGX_ERROR; + } + + h = ngx_hash_key(ctx->name, ngx_strlen(ctx->name)); + pctx = &pacf->ctx[h % pacf->nbuckets]; + + while (*pctx && *pctx != ctx) { + pctx = &(*pctx)->next; + } + + if (*pctx == NULL) { + return NGX_ERROR; + } + + *pctx = (*pctx)->next; + ctx->joined = 0; + + return NGX_OK; +} + + +static void +ngx_rtmp_play_send(ngx_event_t *e) +{ + ngx_rtmp_session_t *s = e->data; + ngx_rtmp_play_ctx_t *ctx; + ngx_int_t rc; + ngx_uint_t ts; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL || ctx->fmt == NULL || ctx->fmt->send == NULL) { + return; + } + + ts = 0; + + rc = ctx->fmt->send(s, &ctx->file, &ts); + + if (rc > 0) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: send schedule %i", rc); + + ngx_add_timer(e, rc); + return; + } + + if (rc == NGX_AGAIN) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: send buffer full"); + + ngx_post_event(e, &s->posted_dry_events); + return; + } + + if (rc == NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: send restart"); + + ngx_post_event(e, &ngx_posted_events); + return; + } + + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: send done"); + + ngx_rtmp_send_stream_eof(s, NGX_RTMP_MSID); + + ngx_rtmp_send_play_status(s, "NetStream.Play.Complete", "status", ts, 0); + + ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", "Stopped"); +} + + +static ngx_int_t +ngx_rtmp_play_do_init(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ctx->fmt && ctx->fmt->init && + ctx->fmt->init(s, &ctx->file, ctx->aindex, ctx->vindex) != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_play_do_done(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ctx->fmt && ctx->fmt->done && + ctx->fmt->done(s, &ctx->file) != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_play_do_start(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: start"); + + if (ctx->fmt && ctx->fmt->start && + ctx->fmt->start(s, &ctx->file) != NGX_OK) + { + return NGX_ERROR; + } + + ngx_post_event((&ctx->send_evt), &ngx_posted_events); + + ctx->playing = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_play_do_seek(ngx_rtmp_session_t *s, ngx_uint_t timestamp) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: seek timestamp=%ui", timestamp); + + if (ctx->fmt && ctx->fmt->seek && + ctx->fmt->seek(s, &ctx->file, timestamp) != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->playing) { + ngx_post_event((&ctx->send_evt), &ngx_posted_events); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_play_do_stop(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: stop"); + + if (ctx->send_evt.timer_set) { + ngx_del_timer(&ctx->send_evt); + } + +#if (nginx_version >= 1007005) + if (ctx->send_evt.posted) +#else + if (ctx->send_evt.prev) +#endif + { + ngx_delete_posted_event((&ctx->send_evt)); + } + + if (ctx->fmt && ctx->fmt->stop && + ctx->fmt->stop(s, &ctx->file) != NGX_OK) + { + return NGX_ERROR; + } + + ctx->playing = 0; + + return NGX_OK; +} + + +/* This function returns pointer to a static buffer */ + +static u_char * +ngx_rtmp_play_get_local_file_path(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_app_conf_t *pacf; + ngx_rtmp_play_ctx_t *ctx; + u_char *p; + static u_char path[NGX_MAX_PATH + 1]; + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + p = ngx_snprintf(path, NGX_MAX_PATH, "%V/" NGX_RTMP_PLAY_TMP_FILE "%ui", + &pacf->temp_path, ctx->file_id); + *p = 0; + + return path; +} + + +static void +ngx_rtmp_play_copy_local_file(ngx_rtmp_session_t *s, u_char *name) +{ + ngx_rtmp_play_app_conf_t *pacf; + ngx_rtmp_play_ctx_t *ctx; + u_char *path, *p; + static u_char dpath[NGX_MAX_PATH + 1]; + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + if (pacf == NULL) { + return; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + if (ctx == NULL || ctx->file_id == 0) { + return; + } + + path = ngx_rtmp_play_get_local_file_path(s); + + p = ngx_snprintf(dpath, NGX_MAX_PATH, "%V/%s%V", &pacf->local_path, + name + ctx->pfx_size, &ctx->sfx); + *p = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: copy local file '%s' to '%s'", path, dpath); + + if (ngx_rename_file(path, dpath) == 0) { + ctx->file_id = 0; + return; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, ngx_errno, + "play: error copying local file '%s' to '%s'", + path, dpath); + + ngx_rtmp_play_cleanup_local_file(s); +} + + +static void +ngx_rtmp_play_cleanup_local_file(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_ctx_t *ctx; + u_char *path; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + if (ctx == NULL || ctx->file_id == 0) { + return; + } + + path = ngx_rtmp_play_get_local_file_path(s); + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: deleting local file '%s'", path); + + ctx->file_id = 0; + + ngx_delete_file(path); +} + + +static ngx_int_t +ngx_rtmp_play_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + if (ctx == NULL) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: close_stream"); + + ngx_rtmp_play_do_stop(s); + + ngx_rtmp_play_do_done(s); + + if (ctx->file.fd != NGX_INVALID_FILE) { + ngx_close_file(ctx->file.fd); + ctx->file.fd = NGX_INVALID_FILE; + + ngx_rtmp_send_stream_eof(s, NGX_RTMP_MSID); + + ngx_rtmp_send_status(s, "NetStream.Play.Stop", "status", + "Stop video on demand"); + } + + if (ctx->file_id) { + ngx_rtmp_play_cleanup_local_file(s); + } + + ngx_rtmp_play_leave(s); + +next: + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_play_seek(ngx_rtmp_session_t *s, ngx_rtmp_seek_t *v) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + if (ctx == NULL || ctx->file.fd == NGX_INVALID_FILE) { + goto next; + } + + if (!ctx->opened) { + ctx->post_seek = (ngx_uint_t) v->offset; + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: post seek=%ui", ctx->post_seek); + goto next; + } + + if (ngx_rtmp_send_stream_eof(s, NGX_RTMP_MSID) != NGX_OK) { + return NGX_ERROR; + } + + ngx_rtmp_play_do_seek(s, (ngx_uint_t) v->offset); + + if (ngx_rtmp_send_status(s, "NetStream.Seek.Notify", "status", "Seeking") + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_rtmp_send_stream_begin(s, NGX_RTMP_MSID) != NGX_OK) { + return NGX_ERROR; + } + +next: + return next_seek(s, v); +} + + +static ngx_int_t +ngx_rtmp_play_pause(ngx_rtmp_session_t *s, ngx_rtmp_pause_t *v) +{ + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx == NULL || ctx->file.fd == NGX_INVALID_FILE) { + goto next; + } + + if (!ctx->opened) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: pause ignored"); + goto next; + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: pause=%i timestamp=%f", + (ngx_int_t) v->pause, v->position); + + if (v->pause) { + if (ngx_rtmp_send_status(s, "NetStream.Pause.Notify", "status", + "Paused video on demand") + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_rtmp_play_do_stop(s); + + } else { + if (ngx_rtmp_send_status(s, "NetStream.Unpause.Notify", "status", + "Unpaused video on demand") + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_rtmp_play_do_start(s); /*TODO: v->position? */ + } + +next: + return next_pause(s, v); +} + + +static ngx_int_t +ngx_rtmp_play_parse_index(char type, u_char *args) +{ + u_char *p, c; + static u_char name[] = "xindex="; + + name[0] = (u_char) type; + + for ( ;; ) { + p = (u_char *) ngx_strstr(args, name); + if (p == NULL) { + return 0; + } + + if (p != args) { + c = *(p - 1); + if (c != '?' && c != '&') { + args = p + 1; + continue; + } + } + + return atoi((char *) p + (sizeof(name) - 1)); + } +} + + +static ngx_int_t +ngx_rtmp_play_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_play_main_conf_t *pmcf; + ngx_rtmp_play_app_conf_t *pacf; + ngx_rtmp_play_ctx_t *ctx; + u_char *p; + ngx_rtmp_play_fmt_t *fmt, **pfmt; + ngx_str_t *pfx, *sfx; + ngx_str_t name; + ngx_uint_t n; + + pmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_play_module); + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + if (pacf == NULL || pacf->entries.nelts == 0) { + goto next; + } + + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "play: play name='%s' timestamp=%i", + v->name, (ngx_int_t) v->start); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx && ctx->file.fd != NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "play: already playing"); + goto next; + } + + /* check for double-dot in v->name; + * we should not move out of play directory */ + for (p = v->name; *p; ++p) { + if (ngx_path_separator(p[0]) && + p[1] == '.' && p[2] == '.' && + ngx_path_separator(p[3])) + { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "play: bad name '%s'", v->name); + return NGX_ERROR; + } + } + + if (ctx == NULL) { + ctx = ngx_palloc(s->connection->pool, sizeof(ngx_rtmp_play_ctx_t)); + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_play_module); + } + + ngx_memzero(ctx, sizeof(*ctx)); + + ctx->session = s; + ctx->aindex = ngx_rtmp_play_parse_index('a', v->args); + ctx->vindex = ngx_rtmp_play_parse_index('v', v->args); + + ctx->file.log = s->connection->log; + + ngx_memcpy(ctx->name, v->name, NGX_RTMP_MAX_NAME); + + name.len = ngx_strlen(v->name); + name.data = v->name; + + pfmt = pmcf->fmts.elts; + + for (n = 0; n < pmcf->fmts.nelts; ++n, ++pfmt) { + fmt = *pfmt; + + pfx = &fmt->pfx; + sfx = &fmt->sfx; + + if (pfx->len == 0 && ctx->fmt == NULL) { + ctx->fmt = fmt; + } + + if (pfx->len && name.len >= pfx->len && + ngx_strncasecmp(pfx->data, name.data, pfx->len) == 0) + { + ctx->pfx_size = pfx->len; + ctx->fmt = fmt; + + break; + } + + if (name.len >= sfx->len && + ngx_strncasecmp(sfx->data, name.data + name.len - sfx->len, + sfx->len) == 0) + { + ctx->fmt = fmt; + } + } + + if (ctx->fmt == NULL) { + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "play: fmt not found"); + goto next; + } + + ctx->file.fd = NGX_INVALID_FILE; + ctx->nentry = NGX_CONF_UNSET_UINT; + ctx->post_seek = NGX_CONF_UNSET_UINT; + + sfx = &ctx->fmt->sfx; + + if (name.len < sfx->len || + ngx_strncasecmp(sfx->data, name.data + name.len - sfx->len, + sfx->len)) + { + ctx->sfx = *sfx; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: fmt=%V", &ctx->fmt->name); + + return ngx_rtmp_play_next_entry(s, v); + +next: + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_play_next_entry(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_play_app_conf_t *pacf; + ngx_rtmp_play_ctx_t *ctx; + ngx_rtmp_play_entry_t *pe; + u_char *p; + static u_char path[NGX_MAX_PATH + 1]; + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + for ( ;; ) { + + if (ctx->file.fd != NGX_INVALID_FILE) { + ngx_close_file(ctx->file.fd); + ctx->file.fd = NGX_INVALID_FILE; + } + + if (ctx->file_id) { + ngx_rtmp_play_cleanup_local_file(s); + } + + ctx->nentry = (ctx->nentry == NGX_CONF_UNSET_UINT ? + 0 : ctx->nentry + 1); + + if (ctx->nentry >= pacf->entries.nelts) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: all entries failed"); + + ngx_rtmp_send_status(s, "NetStream.Play.StreamNotFound", "error", + "Video on demand stream not found"); + break; + } + + pe = ngx_rtmp_play_get_current_entry(s); + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: trying %s entry %ui/%uz '%V'", + pe->url ? "remote" : "local", + ctx->nentry + 1, pacf->entries.nelts, + pe->url ? &pe->url->url : pe->root); + + /* open remote */ + + if (pe->url) { + return ngx_rtmp_play_open_remote(s, v); + } + + /* open local */ + + p = ngx_snprintf(path, NGX_MAX_PATH, "%V/%s%V", + pe->root, v->name + ctx->pfx_size, &ctx->sfx); + *p = 0; + + ctx->file.fd = ngx_open_file(path, NGX_FILE_RDONLY, NGX_FILE_OPEN, + NGX_FILE_DEFAULT_ACCESS); + + if (ctx->file.fd == NGX_INVALID_FILE) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, ngx_errno, + "play: error opening file '%s'", path); + continue; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: open local file '%s'", path); + + if (ngx_rtmp_play_open(s, v->start) != NGX_OK) { + return NGX_ERROR; + } + + break; + } + + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_play_open(ngx_rtmp_session_t *s, double start) +{ + ngx_rtmp_play_ctx_t *ctx; + ngx_event_t *e; + ngx_uint_t timestamp; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx->file.fd == NGX_INVALID_FILE) { + return NGX_ERROR; + } + + if (ngx_rtmp_send_stream_begin(s, NGX_RTMP_MSID) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_send_status(s, "NetStream.Play.Start", "status", + "Start video on demand") + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_rtmp_play_join(s) != NGX_OK) { + return NGX_ERROR; + } + + e = &ctx->send_evt; + e->data = s; + e->handler = ngx_rtmp_play_send; + e->log = s->connection->log; + + ngx_rtmp_send_recorded(s, 1); + + if (ngx_rtmp_send_sample_access(s) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_play_do_init(s) != NGX_OK) { + return NGX_ERROR; + } + + timestamp = ctx->post_seek != NGX_CONF_UNSET_UINT ? ctx->post_seek : + (start < 0 ? 0 : (ngx_uint_t) start); + + if (ngx_rtmp_play_do_seek(s, timestamp) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_play_do_start(s) != NGX_OK) { + return NGX_ERROR; + } + + ctx->opened = 1; + + return NGX_OK; +} + + +static ngx_chain_t * +ngx_rtmp_play_remote_create(ngx_rtmp_session_t *s, void *arg, ngx_pool_t *pool) +{ + ngx_rtmp_play_t *v = arg; + + ngx_rtmp_play_ctx_t *ctx; + ngx_rtmp_play_entry_t *pe; + ngx_str_t *addr_text, uri; + u_char *p, *name; + size_t args_len, name_len, len; + static ngx_str_t text_plain = ngx_string("text/plain"); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + pe = ngx_rtmp_play_get_current_entry(s); + + name = v->name + ctx->pfx_size; + + name_len = ngx_strlen(name); + args_len = ngx_strlen(v->args); + addr_text = &s->connection->addr_text; + + len = pe->url->uri.len + 1 + + name_len + ctx->sfx.len + + sizeof("?addr=") + addr_text->len * 3 + + 1 + args_len; + + uri.data = ngx_palloc(pool, len); + if (uri.data == NULL) { + return NULL; + } + + p = uri.data; + + p = ngx_cpymem(p, pe->url->uri.data, pe->url->uri.len); + + if (p == uri.data || p[-1] != '/') { + *p++ = '/'; + } + + p = ngx_cpymem(p, name, name_len); + p = ngx_cpymem(p, ctx->sfx.data, ctx->sfx.len); + p = ngx_cpymem(p, (u_char*)"?addr=", sizeof("&addr=") -1); + p = (u_char*)ngx_escape_uri(p, addr_text->data, addr_text->len, + NGX_ESCAPE_ARGS); + if (args_len) { + *p++ = '&'; + p = (u_char *) ngx_cpymem(p, v->args, args_len); + } + + uri.len = p - uri.data; + + return ngx_rtmp_netcall_http_format_request(NGX_RTMP_NETCALL_HTTP_GET, + &pe->url->host, &uri, + NULL, NULL, pool, &text_plain); +} + + +static ngx_int_t +ngx_rtmp_play_remote_handle(ngx_rtmp_session_t *s, void *arg, ngx_chain_t *in) +{ + ngx_rtmp_play_t *v = arg; + + ngx_rtmp_play_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + if (ctx->nbody == 0) { + return ngx_rtmp_play_next_entry(s, v); + } + + if (ctx->file_id) { + ngx_rtmp_play_copy_local_file(s, v->name); + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: open remote file"); + + if (ngx_rtmp_play_open(s, v->start) != NGX_OK) { + return NGX_ERROR; + } + + return next_play(s, (ngx_rtmp_play_t *)arg); +} + + +static ngx_int_t +ngx_rtmp_play_remote_sink(ngx_rtmp_session_t *s, ngx_chain_t *in) +{ + ngx_rtmp_play_ctx_t *ctx; + ngx_buf_t *b; + ngx_int_t rc; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + /* skip HTTP header */ + while (in && ctx->ncrs != 2) { + b = in->buf; + + for (; b->pos != b->last && ctx->ncrs != 2; ++b->pos) { + switch (*b->pos) { + case '\n': + ++ctx->ncrs; + case '\r': + break; + default: + ctx->ncrs = 0; + } + /* 10th header byte is HTTP response header */ + if (++ctx->nheader == 10 && *b->pos != (u_char) '2') { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "play: remote HTTP response code: %cxx", + *b->pos); + return NGX_ERROR; + } + } + + if (b->pos == b->last) { + in = in->next; + } + } + + /* write to temp file */ + for (; in; in = in->next) { + b = in->buf; + + if (b->pos == b->last) { + continue; + } + + rc = ngx_write_fd(ctx->file.fd, b->pos, b->last - b->pos); + + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, ngx_errno, + "play: error writing to temp file"); + return NGX_ERROR; + } + + ctx->nbody += rc; + } + + return NGX_OK; +} + + +static ngx_rtmp_play_entry_t * +ngx_rtmp_play_get_current_entry(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_app_conf_t *pacf; + ngx_rtmp_play_ctx_t *ctx; + ngx_rtmp_play_entry_t **ppe; + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + ppe = pacf->entries.elts; + + return ppe[ctx->nentry]; +} + + +static ngx_int_t +ngx_rtmp_play_open_remote(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_play_app_conf_t *pacf; + ngx_rtmp_play_ctx_t *ctx; + ngx_rtmp_play_entry_t *pe; + ngx_rtmp_netcall_init_t ci; + u_char *path; + ngx_err_t err; + static ngx_uint_t file_id; + + pacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_play_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_play_module); + + ctx->ncrs = 0; + ctx->nheader = 0; + ctx->nbody = 0; + + for ( ;; ) { + ctx->file_id = ++file_id; + + /* no zero after overflow */ + if (ctx->file_id == 0) { + continue; + } + + path = ngx_rtmp_play_get_local_file_path(s); + + ctx->file.fd = ngx_open_tempfile(path, pacf->local_path.len, 0); + + if (pacf->local_path.len == 0) { + ctx->file_id = 0; + } + + if (ctx->file.fd != NGX_INVALID_FILE) { + break; + } + + err = ngx_errno; + + if (err != NGX_EEXIST) { + ctx->file_id = 0; + + ngx_log_error(NGX_LOG_INFO, s->connection->log, err, + "play: failed to create temp file"); + + return NGX_ERROR; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "play: temp file '%s' file_id=%ui", + path, ctx->file_id); + + pe = ngx_rtmp_play_get_current_entry(s); + + ngx_memzero(&ci, sizeof(ci)); + + ci.url = pe->url; + ci.create = ngx_rtmp_play_remote_create; + ci.sink = ngx_rtmp_play_remote_sink; + ci.handle = ngx_rtmp_play_remote_handle; + ci.arg = v; + ci.argsize = sizeof(*v); + + return ngx_rtmp_netcall_create(s, &ci); +} + + +static char * +ngx_rtmp_play_url(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_rtmp_play_app_conf_t *pacf = conf; + + ngx_rtmp_play_entry_t *pe, **ppe; + ngx_str_t url; + ngx_url_t *u; + size_t add, n; + ngx_str_t *value; + + if (pacf->entries.nalloc == 0 && + ngx_array_init(&pacf->entries, cf->pool, 1, sizeof(void *)) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + for (n = 1; n < cf->args->nelts; ++n) { + + ppe = ngx_array_push(&pacf->entries); + if (ppe == NULL) { + return NGX_CONF_ERROR; + } + + pe = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_play_entry_t)); + if (pe == NULL) { + return NGX_CONF_ERROR; + } + + *ppe = pe; + + if (ngx_strncasecmp(value[n].data, (u_char *) "http://", 7)) { + + /* local file */ + + pe->root = ngx_palloc(cf->pool, sizeof(ngx_str_t)); + if (pe->root == NULL) { + return NGX_CONF_ERROR; + } + + *pe->root = value[n]; + + continue; + } + + /* http case */ + + url = value[n]; + + add = sizeof("http://") - 1; + + url.data += add; + url.len -= add; + + u = ngx_pcalloc(cf->pool, sizeof(ngx_url_t)); + if (u == NULL) { + return NGX_CONF_ERROR; + } + + u->url.len = url.len; + u->url.data = url.data; + u->default_port = 80; + u->uri_part = 1; + + if (ngx_parse_url(cf->pool, u) != NGX_OK) { + if (u->err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in url \"%V\"", u->err, &u->url); + } + return NGX_CONF_ERROR; + } + + pe->url = u; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_play_postconfiguration(ngx_conf_t *cf) +{ + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_play_play; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_play_close_stream; + + next_seek = ngx_rtmp_seek; + ngx_rtmp_seek = ngx_rtmp_play_seek; + + next_pause = ngx_rtmp_pause; + ngx_rtmp_pause = ngx_rtmp_play_pause; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_play_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_play_module.h new file mode 100644 index 0000000..b0650b5 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_play_module.h @@ -0,0 +1,93 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_PLAY_H_INCLUDED_ +#define _NGX_RTMP_PLAY_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" + + +typedef ngx_int_t (*ngx_rtmp_play_init_pt) (ngx_rtmp_session_t *s, + ngx_file_t *f, ngx_int_t aindex, ngx_int_t vindex); +typedef ngx_int_t (*ngx_rtmp_play_done_pt) (ngx_rtmp_session_t *s, + ngx_file_t *f); +typedef ngx_int_t (*ngx_rtmp_play_start_pt) (ngx_rtmp_session_t *s, + ngx_file_t *f); +typedef ngx_int_t (*ngx_rtmp_play_seek_pt) (ngx_rtmp_session_t *s, + ngx_file_t *f, ngx_uint_t offs); +typedef ngx_int_t (*ngx_rtmp_play_stop_pt) (ngx_rtmp_session_t *s, + ngx_file_t *f); +typedef ngx_int_t (*ngx_rtmp_play_send_pt) (ngx_rtmp_session_t *s, + ngx_file_t *f, ngx_uint_t *ts); + + +typedef struct { + ngx_str_t name; + ngx_str_t pfx; + ngx_str_t sfx; + + ngx_rtmp_play_init_pt init; + ngx_rtmp_play_done_pt done; + ngx_rtmp_play_start_pt start; + ngx_rtmp_play_seek_pt seek; + ngx_rtmp_play_stop_pt stop; + ngx_rtmp_play_send_pt send; +} ngx_rtmp_play_fmt_t; + + +typedef struct ngx_rtmp_play_ctx_s ngx_rtmp_play_ctx_t; + + +struct ngx_rtmp_play_ctx_s { + ngx_rtmp_session_t *session; + ngx_file_t file; + ngx_rtmp_play_fmt_t *fmt; + ngx_event_t send_evt; + unsigned playing:1; + unsigned opened:1; + unsigned joined:1; + ngx_uint_t ncrs; + ngx_uint_t nheader; + ngx_uint_t nbody; + size_t pfx_size; + ngx_str_t sfx; + ngx_uint_t file_id; + ngx_int_t aindex, vindex; + ngx_uint_t nentry; + ngx_uint_t post_seek; + u_char name[NGX_RTMP_MAX_NAME]; + ngx_rtmp_play_ctx_t *next; +}; + + +typedef struct { + ngx_str_t *root; + ngx_url_t *url; +} ngx_rtmp_play_entry_t; + + +typedef struct { + ngx_str_t temp_path; + ngx_str_t local_path; + ngx_array_t entries; /* ngx_rtmp_play_entry_t * */ + ngx_uint_t nbuckets; + ngx_rtmp_play_ctx_t **ctx; +} ngx_rtmp_play_app_conf_t; + + +typedef struct { + ngx_array_t fmts; /* ngx_rtmp_play_fmt_t * */ +} ngx_rtmp_play_main_conf_t; + + +extern ngx_module_t ngx_rtmp_play_module; + + +#endif /* _NGX_RTMP_PLAY_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c b/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c new file mode 100644 index 0000000..ffa2680 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c @@ -0,0 +1,197 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include "ngx_rtmp_proxy_protocol.h" + + +static void ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev); + + +void +ngx_rtmp_proxy_protocol(ngx_rtmp_session_t *s) +{ + ngx_event_t *rev; + ngx_connection_t *c; + + c = s->connection; + rev = c->read; + rev->handler = ngx_rtmp_proxy_protocol_recv; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "proxy_protocol: start"); + + if (rev->ready) { + /* the deferred accept(), rtsig, aio, iocp */ + + if (ngx_use_accept_mutex) { + ngx_post_event(rev, &ngx_posted_events); + return; + } + + rev->handler(rev); + return; + } + + ngx_add_timer(rev, s->timeout); + + if (ngx_handle_read_event(rev, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + return; + } +} + + +static void +ngx_rtmp_proxy_protocol_recv(ngx_event_t *rev) +{ + u_char buf[107], *p, *pp, *text; + size_t len; + ssize_t n; + ngx_err_t err; + ngx_int_t i; + ngx_addr_t addr; + ngx_connection_t *c; + ngx_rtmp_session_t *s; + + c = rev->data; + s = c->data; + + if (c->destroyed) { + return; + } + + if (rev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, + "proxy_protocol: recv: client timed out"); + c->timedout = 1; + ngx_rtmp_finalize_session(s); + return; + } + + if (rev->timer_set) { + ngx_del_timer(rev); + } + + n = recv(c->fd, (char *) buf, sizeof(buf), MSG_PEEK); + + err = ngx_socket_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, "recv(): %d", n); + + if (n == -1) { + + if (err == NGX_EAGAIN) { + ngx_add_timer(rev, s->timeout); + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + ngx_rtmp_finalize_session(s); + } + + return; + } + + ngx_rtmp_finalize_session(s); + + return; + } + + p = buf; + + if (n <= 8 && ngx_strncmp(p, "PROXY ", 6) != 0) { + goto bad_header; + } + + n -= 6; + p += 6; + + ngx_memzero(&addr, sizeof(ngx_addr_t)); + + if (n >= 7 && ngx_strncmp(p, "UNKNOWN", 7) == 0) { + n -= 7; + p += 7; + goto skip; + } + + if (n < 5 || ngx_strncmp(p, "TCP", 3) != 0 + || (p[3] != '4' && p[3] != '6') || p[4] != ' ') + { + goto bad_header; + } + + n -= 5; + p += 5; + + pp = ngx_strlchr(p, p + n, ' '); + + if (pp == NULL) { + goto bad_header; + } + + if (ngx_parse_addr(s->connection->pool, &addr, p, pp - p) != NGX_OK) { + goto bad_header; + } + + n -= pp - p; + p = pp; + +skip: + + for (i = 0; i + 1 < n; i++) { + if (p[i] == CR && p[i + 1] == LF) { + break; + } + } + + if (i + 1 >= n) { + goto bad_header; + } + + n = p - buf + i + 2; + + if (c->recv(c, buf, n) != n) { + goto failed; + } + + if (addr.socklen) { + text = ngx_palloc(s->connection->pool, NGX_SOCKADDR_STRLEN); + + if (text == NULL) { + goto failed; + } + + len = ngx_sock_ntop(addr.sockaddr, +#if (nginx_version >= 1005003) + addr.socklen, +#endif + text, NGX_SOCKADDR_STRLEN, 0); + if (len == 0) { + goto failed; + } + + c->sockaddr = addr.sockaddr; + c->socklen = addr.socklen; + c->addr_text.data = text; + c->addr_text.len = len; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, c->log, 0, + "proxy_protocol: remote_addr:'%V'", &c->addr_text); + } + + ngx_rtmp_handshake(s); + + return; + +bad_header: + + ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxy_protocol: bad header"); + +failed: + + ngx_rtmp_finalize_session(s); +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h b/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h new file mode 100644 index 0000000..e873c3c --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ +#define _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +void ngx_rtmp_proxy_protocol(ngx_rtmp_session_t *c); + + +#endif /* _NGX_RTMP_PROXY_PROTOCOL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_receive.c b/debian/modules/nginx-rtmp/ngx_rtmp_receive.c new file mode 100644 index 0000000..73d617c --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_receive.c @@ -0,0 +1,464 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_amf.h" +#include "ngx_rtmp_cmd_module.h" +#include + + +ngx_int_t +ngx_rtmp_protocol_message_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + ngx_buf_t *b; + u_char *p; + uint32_t val; + uint8_t limit; + + b = in->buf; + + if (b->last - b->pos < 4) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "too small buffer for %d message: %d", + (int)h->type, b->last - b->pos); + return NGX_OK; + } + + p = (u_char*)&val; + p[0] = b->pos[3]; + p[1] = b->pos[2]; + p[2] = b->pos[1]; + p[3] = b->pos[0]; + + switch(h->type) { + case NGX_RTMP_MSG_CHUNK_SIZE: + /* set chunk size =val */ + ngx_rtmp_set_chunk_size(s, val); + break; + + case NGX_RTMP_MSG_ABORT: + /* abort chunk stream =val */ + break; + + case NGX_RTMP_MSG_ACK: + /* receive ack with sequence number =val */ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive ack seq=%uD", val); + break; + + case NGX_RTMP_MSG_ACK_SIZE: + /* receive window size =val */ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive ack_size=%uD", val); + s->ack_size = val; + break; + + case NGX_RTMP_MSG_BANDWIDTH: + if (b->last - b->pos >= 5) { + limit = *(uint8_t*)&b->pos[4]; + + (void)val; + (void)limit; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive bandwidth=%uD limit=%d", + val, (int)limit); + + /* receive window size =val + * && limit */ + } + break; + + default: + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_user_message_handler(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_buf_t *b; + u_char *p; + uint16_t evt; + uint32_t val; + + b = in->buf; + + if (b->last - b->pos < 6) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "too small buffer for user message: %d", + b->last - b->pos); + return NGX_OK; + } + + p = (u_char*)&evt; + + p[0] = b->pos[1]; + p[1] = b->pos[0]; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP recv user evt %s (%i)", + ngx_rtmp_user_message_type(evt), (ngx_int_t) evt); + + p = (u_char *) &val; + + p[0] = b->pos[5]; + p[1] = b->pos[4]; + p[2] = b->pos[3]; + p[3] = b->pos[2]; + + switch(evt) { + case NGX_RTMP_USER_STREAM_BEGIN: + { + ngx_rtmp_stream_begin_t v; + + v.msid = val; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive: stream_begin msid=%uD", v.msid); + + return ngx_rtmp_stream_begin(s, &v); + } + + case NGX_RTMP_USER_STREAM_EOF: + { + ngx_rtmp_stream_eof_t v; + + v.msid = val; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive: stream_eof msid=%uD", v.msid); + + return ngx_rtmp_stream_eof(s, &v); + } + + case NGX_RTMP_USER_STREAM_DRY: + { + ngx_rtmp_stream_dry_t v; + + v.msid = val; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive: stream_dry msid=%uD", v.msid); + + return ngx_rtmp_stream_dry(s, &v); + } + + case NGX_RTMP_USER_SET_BUFLEN: + { + ngx_rtmp_set_buflen_t v; + + v.msid = val; + + if (b->last - b->pos < 10) { + return NGX_OK; + } + + p = (u_char *) &v.buflen; + + p[0] = b->pos[9]; + p[1] = b->pos[8]; + p[2] = b->pos[7]; + p[3] = b->pos[6]; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive: set_buflen msid=%uD buflen=%uD", + v.msid, v.buflen); + + /*TODO: move this to play module */ + s->buflen = v.buflen; + + return ngx_rtmp_set_buflen(s, &v); + } + + case NGX_RTMP_USER_RECORDED: + { + ngx_rtmp_recorded_t v; + + v.msid = val; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "receive: recorded msid=%uD", v.msid); + + return ngx_rtmp_recorded(s, &v); + } + + case NGX_RTMP_USER_PING_REQUEST: + return ngx_rtmp_send_ping_response(s, val); + + case NGX_RTMP_USER_PING_RESPONSE: + + /* val = incoming timestamp */ + + ngx_rtmp_reset_ping(s); + + return NGX_OK; + + default: + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "unexpected user event: %i", (ngx_int_t) evt); + + return NGX_OK; + } +} + + +static ngx_int_t +ngx_rtmp_fetch(ngx_chain_t **in, u_char *ret) +{ + while (*in && (*in)->buf->pos >= (*in)->buf->last) { + *in = (*in)->next; + } + + if (*in == NULL) { + return NGX_DONE; + } + + *ret = *(*in)->buf->pos++; + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_fetch_uint8(ngx_chain_t **in, uint8_t *ret) +{ + return ngx_rtmp_fetch(in, (u_char *) ret); +} + + +static ngx_int_t +ngx_rtmp_fetch_uint32(ngx_chain_t **in, uint32_t *ret, ngx_int_t n) +{ + u_char *r = (u_char *) ret; + ngx_int_t rc; + + *ret = 0; + + while (--n >= 0) { + rc = ngx_rtmp_fetch(in, &r[n]); + if (rc != NGX_OK) { + return rc; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_aggregate_message_handler(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + uint32_t base_time, timestamp, prev_size; + size_t len; + ngx_int_t first; + u_char *last; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *cl, *next; + ngx_rtmp_header_t ch; + + ch = *h; + + first = 1; + base_time = 0; + + while (in) { + if (ngx_rtmp_fetch_uint8(&in, &ch.type) != NGX_OK) { + return NGX_OK; + } + + if (ngx_rtmp_fetch_uint32(&in, &ch.mlen, 3) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_fetch_uint32(&in, ×tamp, 3) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_rtmp_fetch_uint8(&in, (uint8_t *) ×tamp + 3) != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_rtmp_fetch_uint32(&in, &ch.msid, 3) != NGX_OK) + { + return NGX_ERROR; + } + + if (first) { + base_time = timestamp; + first = 0; + } + + ngx_log_debug6(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP aggregate %s (%d) len=%uD time=%uD (+%D) msid=%uD", + ngx_rtmp_message_type(ch.type), + (ngx_int_t) ch.type, ch.mlen, ch.timestamp, + timestamp - base_time, ch.msid); + + /* limit chain */ + + len = 0; + cl = in; + while (cl) { + b = cl->buf; + len += (b->last - b->pos); + if (len > ch.mlen) { + break; + } + cl = cl->next; + } + + if (cl == NULL) { + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "RTMP error parsing aggregate"); + return NGX_ERROR; + } + + next = cl->next; + cl->next = NULL; + b = cl->buf; + last = b->last; + b->last -= (len - ch.mlen); + + /* handle aggregated message */ + + ch.timestamp = h->timestamp + timestamp - base_time; + + rc = ngx_rtmp_receive_message(s, &ch, in); + + /* restore chain before checking the result */ + + in = cl; + in->next = next; + b->pos = b->last; + b->last = last; + + if (rc != NGX_OK) { + return rc; + } + + /* read 32-bit previous tag size */ + + if (ngx_rtmp_fetch_uint32(&in, &prev_size, 4) != NGX_OK) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "RTMP aggregate prev_size=%uD", prev_size); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_amf_message_handler(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + ngx_rtmp_amf_ctx_t act; + ngx_rtmp_core_main_conf_t *cmcf; + ngx_array_t *ch; + ngx_rtmp_handler_pt *ph; + size_t len, n; + + static u_char func[128]; + + static ngx_rtmp_amf_elt_t elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + func, sizeof(func) }, + }; + + /* AMF command names come with string type, but shared object names + * come without type */ + if (h->type == NGX_RTMP_MSG_AMF_SHARED || + h->type == NGX_RTMP_MSG_AMF3_SHARED) + { + elts[0].type |= NGX_RTMP_AMF_TYPELESS; + } else { + elts[0].type &= ~NGX_RTMP_AMF_TYPELESS; + } + + if ((h->type == NGX_RTMP_MSG_AMF3_SHARED || + h->type == NGX_RTMP_MSG_AMF3_META || + h->type == NGX_RTMP_MSG_AMF3_CMD) + && in->buf->last > in->buf->pos) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "AMF3 prefix: %ui", (ngx_int_t)*in->buf->pos); + ++in->buf->pos; + } + + cmcf = ngx_rtmp_get_module_main_conf(s, ngx_rtmp_core_module); + + /* read AMF func name & transaction id */ + ngx_memzero(&act, sizeof(act)); + act.link = in; + act.log = s->connection->log; + memset(func, 0, sizeof(func)); + + if (ngx_rtmp_amf_read(&act, elts, + sizeof(elts) / sizeof(elts[0])) != NGX_OK) + { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "AMF cmd failed"); + return NGX_ERROR; + } + + /* skip name */ + in = act.link; + in->buf->pos += act.offset; + + len = ngx_strlen(func); + + ch = ngx_hash_find(&cmcf->amf_hash, + ngx_hash_strlow(func, func, len), func, len); + + if (ch && ch->nelts) { + ph = ch->elts; + for (n = 0; n < ch->nelts; ++n, ++ph) { + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "AMF func '%s' passed to handler %d/%d", + func, n, ch->nelts); + switch ((*ph)(s, h, in)) { + case NGX_ERROR: + return NGX_ERROR; + case NGX_DONE: + return NGX_OK; + } + } + } else { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "AMF cmd '%s' no handler", func); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_receive_amf(ngx_rtmp_session_t *s, ngx_chain_t *in, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + ngx_rtmp_amf_ctx_t act; + + ngx_memzero(&act, sizeof(act)); + act.link = in; + act.log = s->connection->log; + + return ngx_rtmp_amf_read(&act, elts, nelts); +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_record_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_record_module.c new file mode 100644 index 0000000..dc2de12 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_record_module.c @@ -0,0 +1,1307 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_cmd_module.h" +#include "ngx_rtmp_netcall_module.h" +#include "ngx_rtmp_codec_module.h" +#include "ngx_rtmp_record_module.h" + + +ngx_rtmp_record_done_pt ngx_rtmp_record_done; + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_close_stream_pt next_close_stream; +static ngx_rtmp_stream_begin_pt next_stream_begin; +static ngx_rtmp_stream_eof_pt next_stream_eof; + + +static char *ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_rtmp_record_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_record_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx, + ngx_rtmp_header_t *h, ngx_chain_t *in, ngx_int_t inc_nframes); +static ngx_int_t ngx_rtmp_record_av(ngx_rtmp_session_t *s, + ngx_rtmp_header_t *h, ngx_chain_t *in); +static ngx_int_t ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx, ngx_rtmp_header_t *h, ngx_chain_t *in); +static ngx_int_t ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx); +static ngx_int_t ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx); +static void ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path); +static ngx_int_t ngx_rtmp_record_init(ngx_rtmp_session_t *s); + + +static ngx_conf_bitmask_t ngx_rtmp_record_mask[] = { + { ngx_string("off"), NGX_RTMP_RECORD_OFF }, + { ngx_string("all"), NGX_RTMP_RECORD_AUDIO | + NGX_RTMP_RECORD_VIDEO }, + { ngx_string("audio"), NGX_RTMP_RECORD_AUDIO }, + { ngx_string("video"), NGX_RTMP_RECORD_VIDEO }, + { ngx_string("keyframes"), NGX_RTMP_RECORD_KEYFRAMES }, + { ngx_string("manual"), NGX_RTMP_RECORD_MANUAL }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_rtmp_record_commands[] = { + + { ngx_string("record"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, flags), + ngx_rtmp_record_mask }, + + { ngx_string("record_path"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, path), + NULL }, + + { ngx_string("record_suffix"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, suffix), + NULL }, + + { ngx_string("record_unique"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, unique), + NULL }, + + { ngx_string("record_append"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, append), + NULL }, + + { ngx_string("record_lock"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, lock_file), + NULL }, + + { ngx_string("record_max_size"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, max_size), + NULL }, + + { ngx_string("record_max_frames"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, max_frames), + NULL }, + + { ngx_string("record_interval"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, interval), + NULL }, + + { ngx_string("record_notify"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF| + NGX_RTMP_REC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_record_app_conf_t, notify), + NULL }, + + { ngx_string("recorder"), + NGX_RTMP_APP_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_rtmp_record_recorder, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_record_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_record_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_record_create_app_conf, /* create app configuration */ + ngx_rtmp_record_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_record_module = { + NGX_MODULE_V1, + &ngx_rtmp_record_module_ctx, /* module context */ + ngx_rtmp_record_commands, /* module directives */ + NGX_RTMP_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_rtmp_record_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_record_app_conf_t *racf; + + racf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_record_app_conf_t)); + + if (racf == NULL) { + return NULL; + } + + racf->max_size = NGX_CONF_UNSET_SIZE; + racf->max_frames = NGX_CONF_UNSET_SIZE; + racf->interval = NGX_CONF_UNSET_MSEC; + racf->unique = NGX_CONF_UNSET; + racf->append = NGX_CONF_UNSET; + racf->lock_file = NGX_CONF_UNSET; + racf->notify = NGX_CONF_UNSET; + racf->url = NGX_CONF_UNSET_PTR; + + if (ngx_array_init(&racf->rec, cf->pool, 1, sizeof(void *)) != NGX_OK) { + return NULL; + } + + return racf; +} + + +static char * +ngx_rtmp_record_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_record_app_conf_t *prev = parent; + ngx_rtmp_record_app_conf_t *conf = child; + ngx_rtmp_record_app_conf_t **rracf; + + ngx_conf_merge_str_value(conf->path, prev->path, ""); + ngx_conf_merge_str_value(conf->suffix, prev->suffix, ".flv"); + ngx_conf_merge_size_value(conf->max_size, prev->max_size, 0); + ngx_conf_merge_size_value(conf->max_frames, prev->max_frames, 0); + ngx_conf_merge_value(conf->unique, prev->unique, 0); + ngx_conf_merge_value(conf->append, prev->append, 0); + ngx_conf_merge_value(conf->lock_file, prev->lock_file, 0); + ngx_conf_merge_value(conf->notify, prev->notify, 0); + ngx_conf_merge_msec_value(conf->interval, prev->interval, + (ngx_msec_t) NGX_CONF_UNSET); + ngx_conf_merge_bitmask_value(conf->flags, prev->flags, 0); + ngx_conf_merge_ptr_value(conf->url, prev->url, NULL); + + if (conf->flags) { + rracf = ngx_array_push(&conf->rec); + if (rracf == NULL) { + return NGX_CONF_ERROR; + } + + *rracf = conf; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_record_write_header(ngx_file_t *file) +{ + static u_char flv_header[] = { + 0x46, /* 'F' */ + 0x4c, /* 'L' */ + 0x56, /* 'V' */ + 0x01, /* version = 1 */ + 0x05, /* 00000 1 0 1 = has audio & video */ + 0x00, + 0x00, + 0x00, + 0x09, /* header size */ + 0x00, + 0x00, + 0x00, + 0x00 /* PreviousTagSize0 (not actually a header) */ + }; + + return ngx_write_file(file, flv_header, sizeof(flv_header), 0) == NGX_ERROR + ? NGX_ERROR + : NGX_OK; +} + + +static ngx_rtmp_record_rec_ctx_t * +ngx_rtmp_record_get_node_ctx(ngx_rtmp_session_t *s, ngx_uint_t n) +{ + ngx_rtmp_record_ctx_t *ctx; + ngx_rtmp_record_rec_ctx_t *rctx; + + if (ngx_rtmp_record_init(s) != NGX_OK) { + return NULL; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + + if (n >= ctx->rec.nelts) { + return NULL; + } + + rctx = ctx->rec.elts; + + return &rctx[n]; +} + + +ngx_int_t +ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) +{ + ngx_rtmp_record_rec_ctx_t *rctx; + ngx_int_t rc; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: #%ui manual open", n); + + rctx = ngx_rtmp_record_get_node_ctx(s, n); + + if (rctx == NULL) { + return NGX_ERROR; + } + + rc = ngx_rtmp_record_node_open(s, rctx); + if (rc != NGX_OK) { + return rc; + } + + if (path) { + ngx_rtmp_record_make_path(s, rctx, path); + } + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, ngx_str_t *path) +{ + ngx_rtmp_record_rec_ctx_t *rctx; + ngx_int_t rc; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: #%ui manual close", n); + + rctx = ngx_rtmp_record_get_node_ctx(s, n); + + if (rctx == NULL) { + return NGX_ERROR; + } + + rc = ngx_rtmp_record_node_close(s, rctx); + if (rc != NGX_OK) { + return rc; + } + + if (path) { + ngx_rtmp_record_make_path(s, rctx, path); + } + + return NGX_OK; +} + + +ngx_uint_t +ngx_rtmp_record_find(ngx_rtmp_record_app_conf_t *racf, ngx_str_t *id) +{ + ngx_rtmp_record_app_conf_t **pracf, *rracf; + ngx_uint_t n; + + pracf = racf->rec.elts; + + for (n = 0; n < racf->rec.nelts; ++n, ++pracf) { + rracf = *pracf; + + if (rracf->id.len == id->len && + ngx_strncmp(rracf->id.data, id->data, id->len) == 0) + { + return n; + } + } + + return NGX_CONF_UNSET_UINT; +} + + +/* This funcion returns pointer to a static buffer */ +static void +ngx_rtmp_record_make_path(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx, ngx_str_t *path) +{ + ngx_rtmp_record_ctx_t *ctx; + ngx_rtmp_record_app_conf_t *rracf; + u_char *p, *l; + struct tm tm; + + static u_char buf[NGX_TIME_T_LEN + 1]; + static u_char pbuf[NGX_MAX_PATH + 1]; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + + rracf = rctx->conf; + + /* create file path */ + p = pbuf; + l = pbuf + sizeof(pbuf) - 1; + + p = ngx_cpymem(p, rracf->path.data, + ngx_min(rracf->path.len, (size_t)(l - p - 1))); + *p++ = '/'; + p = (u_char *)ngx_escape_uri(p, ctx->name, ngx_min(ngx_strlen(ctx->name), + (size_t)(l - p)), NGX_ESCAPE_URI_COMPONENT); + + /* append timestamp */ + if (rracf->unique) { + p = ngx_cpymem(p, buf, ngx_min(ngx_sprintf(buf, "-%T", + rctx->timestamp) - buf, l - p)); + } + + if (ngx_strchr(rracf->suffix.data, '%')) { + ngx_libc_localtime(rctx->timestamp, &tm); + p += strftime((char *) p, l - p, (char *) rracf->suffix.data, &tm); + } else { + p = ngx_cpymem(p, rracf->suffix.data, + ngx_min(rracf->suffix.len, (size_t)(l - p))); + } + + *p = 0; + path->data = pbuf; + path->len = p - pbuf; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V path: '%V'", &rracf->id, path); +} + + +static void +ngx_rtmp_record_notify_error(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx) +{ + ngx_rtmp_record_app_conf_t *rracf = rctx->conf; + + rctx->failed = 1; + + if (!rracf->notify) { + return; + } + + ngx_rtmp_send_status(s, "NetStream.Record.Failed", "error", + rracf->id.data ? (char *) rracf->id.data : ""); +} + + +static ngx_int_t +ngx_rtmp_record_node_open(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx) +{ + ngx_rtmp_record_app_conf_t *rracf; + ngx_err_t err; + ngx_str_t path; + ngx_int_t mode, create_mode; + u_char buf[8], *p; + off_t file_size; + uint32_t tag_size, mlen, timestamp; + + rracf = rctx->conf; + tag_size = 0; + + if (rctx->file.fd != NGX_INVALID_FILE) { + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V opening", &rracf->id); + + ngx_memzero(rctx, sizeof(*rctx)); + rctx->conf = rracf; + rctx->last = *ngx_cached_time; + rctx->timestamp = ngx_cached_time->sec; + + ngx_rtmp_record_make_path(s, rctx, &path); + + mode = rracf->append ? NGX_FILE_RDWR : NGX_FILE_WRONLY; + create_mode = rracf->append ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE; + + ngx_memzero(&rctx->file, sizeof(rctx->file)); + rctx->file.offset = 0; + rctx->file.log = s->connection->log; + rctx->file.fd = ngx_open_file(path.data, mode, create_mode, + NGX_FILE_DEFAULT_ACCESS); + ngx_str_set(&rctx->file.name, "recorded"); + + if (rctx->file.fd == NGX_INVALID_FILE) { + err = ngx_errno; + + if (err != NGX_ENOENT) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, + "record: %V failed to open file '%V'", + &rracf->id, &path); + } + + ngx_rtmp_record_notify_error(s, rctx); + + return NGX_OK; + } + +#if !(NGX_WIN32) + if (rracf->lock_file) { + err = ngx_lock_fd(rctx->file.fd); + if (err) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, + "record: %V lock failed", &rracf->id); + } + } +#endif + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V opened '%V'", &rracf->id, &path); + + if (rracf->notify) { + ngx_rtmp_send_status(s, "NetStream.Record.Start", "status", + rracf->id.data ? (char *) rracf->id.data : ""); + } + + if (rracf->append) { + + file_size = 0; + timestamp = 0; + +#if (NGX_WIN32) + { + LONG lo, hi; + + lo = 0; + hi = 0; + lo = SetFilePointer(rctx->file.fd, lo, &hi, FILE_END); + file_size = (lo == INVALID_SET_FILE_POINTER ? + (off_t) -1 : (off_t) hi << 32 | (off_t) lo); + } +#else + file_size = lseek(rctx->file.fd, 0, SEEK_END); +#endif + if (file_size == (off_t) -1) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, + "record: %V seek failed", &rracf->id); + goto done; + } + + if (file_size < 4) { + goto done; + } + + if (ngx_read_file(&rctx->file, buf, 4, file_size - 4) != 4) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, + "record: %V tag size read failed", &rracf->id); + goto done; + } + + p = (u_char *) &tag_size; + p[0] = buf[3]; + p[1] = buf[2]; + p[2] = buf[1]; + p[3] = buf[0]; + + if (tag_size == 0 || tag_size + 4 > file_size) { + file_size = 0; + goto done; + } + + if (ngx_read_file(&rctx->file, buf, 8, file_size - tag_size - 4) != 8) + { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, + "record: %V tag read failed", &rracf->id); + goto done; + } + + p = (u_char *) &mlen; + p[0] = buf[3]; + p[1] = buf[2]; + p[2] = buf[1]; + p[3] = 0; + + if (tag_size != mlen + 11) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, + "record: %V tag size mismatch: " + "tag_size=%uD, mlen=%uD", &rracf->id, tag_size, mlen); + goto done; + } + + p = (u_char *) ×tamp; + p[3] = buf[7]; + p[0] = buf[6]; + p[1] = buf[5]; + p[2] = buf[4]; + +done: + rctx->file.offset = file_size; + rctx->time_shift = timestamp; + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: append offset=%O, time=%uD, tag_size=%uD", + file_size, timestamp, tag_size); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_record_init(ngx_rtmp_session_t *s) +{ + ngx_rtmp_record_app_conf_t *racf, **rracf; + ngx_rtmp_record_rec_ctx_t *rctx; + ngx_rtmp_record_ctx_t *ctx; + ngx_uint_t n; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + + if (ctx) { + return NGX_OK; + } + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); + + if (racf == NULL || racf->rec.nelts == 0) { + return NGX_OK; + } + + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_record_ctx_t)); + + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_record_module); + + if (ngx_array_init(&ctx->rec, s->connection->pool, racf->rec.nelts, + sizeof(ngx_rtmp_record_rec_ctx_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + rracf = racf->rec.elts; + + rctx = ngx_array_push_n(&ctx->rec, racf->rec.nelts); + + if (rctx == NULL) { + return NGX_ERROR; + } + + for (n = 0; n < racf->rec.nelts; ++n, ++rracf, ++rctx) { + ngx_memzero(rctx, sizeof(*rctx)); + + rctx->conf = *rracf; + rctx->file.fd = NGX_INVALID_FILE; + } + + return NGX_OK; +} + + +static void +ngx_rtmp_record_start(ngx_rtmp_session_t *s) +{ + ngx_rtmp_record_app_conf_t *racf; + ngx_rtmp_record_rec_ctx_t *rctx; + ngx_rtmp_record_ctx_t *ctx; + ngx_uint_t n; + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); + if (racf == NULL || racf->rec.nelts == 0) { + return; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + if (ctx == NULL) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: start"); + + rctx = ctx->rec.elts; + for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { + if (rctx->conf->flags & (NGX_RTMP_RECORD_OFF|NGX_RTMP_RECORD_MANUAL)) { + continue; + } + ngx_rtmp_record_node_open(s, rctx); + } +} + + +static void +ngx_rtmp_record_stop(ngx_rtmp_session_t *s) +{ + ngx_rtmp_record_app_conf_t *racf; + ngx_rtmp_record_rec_ctx_t *rctx; + ngx_rtmp_record_ctx_t *ctx; + ngx_uint_t n; + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); + if (racf == NULL || racf->rec.nelts == 0) { + return; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + if (ctx == NULL) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: stop"); + + rctx = ctx->rec.elts; + for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { + ngx_rtmp_record_node_close(s, rctx); + } +} + + +static ngx_int_t +ngx_rtmp_record_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_record_app_conf_t *racf; + ngx_rtmp_record_ctx_t *ctx; + u_char *p; + + if (s->auto_pushed) { + goto next; + } + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_record_module); + + if (racf == NULL || racf->rec.nelts == 0) { + goto next; + } + + if (ngx_rtmp_record_init(s) != NGX_OK) { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: publish %ui nodes", + racf->rec.nelts); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + + ngx_memcpy(ctx->name, v->name, sizeof(ctx->name)); + ngx_memcpy(ctx->args, v->args, sizeof(ctx->args)); + + /* terminate name on /../ */ + for (p = ctx->name; *p; ++p) { + if (ngx_path_separator(p[0]) && + p[1] == '.' && p[2] == '.' && + ngx_path_separator(p[3])) + { + *p = 0; + break; + } + } + + ngx_rtmp_record_start(s); + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_record_stream_begin(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) +{ + if (s->auto_pushed) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: stream_begin"); + + ngx_rtmp_record_start(s); + +next: + return next_stream_begin(s, v); +} + + +static ngx_int_t +ngx_rtmp_record_stream_eof(ngx_rtmp_session_t *s, ngx_rtmp_stream_begin_t *v) +{ + if (s->auto_pushed) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: stream_eof"); + + ngx_rtmp_record_stop(s); + +next: + return next_stream_eof(s, v); +} + + +static ngx_int_t +ngx_rtmp_record_node_close(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx) +{ + ngx_rtmp_record_app_conf_t *rracf; + ngx_err_t err; + void **app_conf; + ngx_int_t rc; + ngx_rtmp_record_done_t v; + u_char av; + + rracf = rctx->conf; + + if (rctx->file.fd == NGX_INVALID_FILE) { + return NGX_AGAIN; + } + + if (rctx->initialized) { + av = 0; + + if (rctx->video) { + av |= 0x01; + } + + if (rctx->audio) { + av |= 0x04; + } + + if (ngx_write_file(&rctx->file, &av, 1, 4) == NGX_ERROR) { + ngx_log_error(NGX_LOG_CRIT, s->connection->log, ngx_errno, + "record: %V error writing av mask", &rracf->id); + } + } + + if (ngx_close_file(rctx->file.fd) == NGX_FILE_ERROR) { + err = ngx_errno; + ngx_log_error(NGX_LOG_CRIT, s->connection->log, err, + "record: %V error closing file", &rracf->id); + + ngx_rtmp_record_notify_error(s, rctx); + } + + rctx->file.fd = NGX_INVALID_FILE; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V closed", &rracf->id); + + if (rracf->notify) { + ngx_rtmp_send_status(s, "NetStream.Record.Stop", "status", + rracf->id.data ? (char *) rracf->id.data : ""); + } + + app_conf = s->app_conf; + + if (rracf->rec_conf) { + s->app_conf = rracf->rec_conf; + } + + v.recorder = rracf->id; + ngx_rtmp_record_make_path(s, rctx, &v.path); + + rc = ngx_rtmp_record_done(s, &v); + + s->app_conf = app_conf; + + return rc; +} + + +static ngx_int_t +ngx_rtmp_record_close_stream(ngx_rtmp_session_t *s, + ngx_rtmp_close_stream_t *v) +{ + if (s->auto_pushed) { + goto next; + } + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: close_stream"); + + ngx_rtmp_record_stop(s); + +next: + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_record_write_frame(ngx_rtmp_session_t *s, + ngx_rtmp_record_rec_ctx_t *rctx, + ngx_rtmp_header_t *h, ngx_chain_t *in, + ngx_int_t inc_nframes) +{ + u_char hdr[11], *p, *ph; + uint32_t timestamp, tag_size; + ngx_rtmp_record_app_conf_t *rracf; + + rracf = rctx->conf; + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V frame: mlen=%uD", + &rracf->id, h->mlen); + + if (h->type == NGX_RTMP_MSG_VIDEO) { + rctx->video = 1; + } else { + rctx->audio = 1; + } + + timestamp = h->timestamp - rctx->epoch; + + if ((int32_t) timestamp < 0) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V cut timestamp=%D", &rracf->id, timestamp); + + timestamp = 0; + } + + /* write tag header */ + ph = hdr; + + *ph++ = (u_char)h->type; + + p = (u_char*)&h->mlen; + *ph++ = p[2]; + *ph++ = p[1]; + *ph++ = p[0]; + + p = (u_char*)×tamp; + *ph++ = p[2]; + *ph++ = p[1]; + *ph++ = p[0]; + *ph++ = p[3]; + + *ph++ = 0; + *ph++ = 0; + *ph++ = 0; + + tag_size = (ph - hdr) + h->mlen; + + if (ngx_write_file(&rctx->file, hdr, ph - hdr, rctx->file.offset) + == NGX_ERROR) + { + ngx_rtmp_record_notify_error(s, rctx); + + ngx_close_file(rctx->file.fd); + + return NGX_ERROR; + } + + /* write tag body + * FIXME: NGINX + * ngx_write_chain seems to fit best + * but it suffers from uncontrollable + * allocations. + * we're left with plain writing */ + for(; in; in = in->next) { + if (in->buf->pos == in->buf->last) { + continue; + } + + if (ngx_write_file(&rctx->file, in->buf->pos, in->buf->last + - in->buf->pos, rctx->file.offset) + == NGX_ERROR) + { + return NGX_ERROR; + } + } + + /* write tag size */ + ph = hdr; + p = (u_char*)&tag_size; + + *ph++ = p[3]; + *ph++ = p[2]; + *ph++ = p[1]; + *ph++ = p[0]; + + if (ngx_write_file(&rctx->file, hdr, ph - hdr, + rctx->file.offset) + == NGX_ERROR) + { + return NGX_ERROR; + } + + rctx->nframes += inc_nframes; + + /* watch max size */ + if ((rracf->max_size && rctx->file.offset >= (ngx_int_t) rracf->max_size) || + (rracf->max_frames && rctx->nframes >= rracf->max_frames)) + { + ngx_rtmp_record_node_close(s, rctx); + } + + return NGX_OK; +} + + +static size_t +ngx_rtmp_record_get_chain_mlen(ngx_chain_t *in) +{ + size_t ret; + + for (ret = 0; in; in = in->next) { + ret += (in->buf->last - in->buf->pos); + } + + return ret; +} + + +static ngx_int_t +ngx_rtmp_record_av(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_record_ctx_t *ctx; + ngx_rtmp_record_rec_ctx_t *rctx; + ngx_uint_t n; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_record_module); + + if (ctx == NULL) { + return NGX_OK; + } + + rctx = ctx->rec.elts; + + for (n = 0; n < ctx->rec.nelts; ++n, ++rctx) { + ngx_rtmp_record_node_av(s, rctx, h, in); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_record_node_av(ngx_rtmp_session_t *s, ngx_rtmp_record_rec_ctx_t *rctx, + ngx_rtmp_header_t *h, ngx_chain_t *in) +{ + ngx_time_t next; + ngx_rtmp_header_t ch; + ngx_rtmp_codec_ctx_t *codec_ctx; + ngx_int_t keyframe, brkframe; + ngx_rtmp_record_app_conf_t *rracf; + + rracf = rctx->conf; + + if (rracf->flags & NGX_RTMP_RECORD_OFF) { + ngx_rtmp_record_node_close(s, rctx); + return NGX_OK; + } + + keyframe = (h->type == NGX_RTMP_MSG_VIDEO) + ? (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME) + : 0; + + brkframe = (h->type == NGX_RTMP_MSG_VIDEO) + ? keyframe + : (rracf->flags & NGX_RTMP_RECORD_VIDEO) == 0; + + if (brkframe && (rracf->flags & NGX_RTMP_RECORD_MANUAL) == 0) { + + if (rracf->interval != (ngx_msec_t) NGX_CONF_UNSET) { + + next = rctx->last; + next.msec += rracf->interval; + next.sec += (next.msec / 1000); + next.msec %= 1000; + + if (ngx_cached_time->sec > next.sec || + (ngx_cached_time->sec == next.sec && + ngx_cached_time->msec > next.msec)) + { + ngx_rtmp_record_node_close(s, rctx); + ngx_rtmp_record_node_open(s, rctx); + } + + } else if (!rctx->failed) { + ngx_rtmp_record_node_open(s, rctx); + } + } + + if ((rracf->flags & NGX_RTMP_RECORD_MANUAL) && + !brkframe && rctx->nframes == 0) + { + return NGX_OK; + } + + if (rctx->file.fd == NGX_INVALID_FILE) { + return NGX_OK; + } + + if (h->type == NGX_RTMP_MSG_AUDIO && + (rracf->flags & NGX_RTMP_RECORD_AUDIO) == 0) + { + return NGX_OK; + } + + if (h->type == NGX_RTMP_MSG_VIDEO && + (rracf->flags & NGX_RTMP_RECORD_VIDEO) == 0 && + ((rracf->flags & NGX_RTMP_RECORD_KEYFRAMES) == 0 || !keyframe)) + { + return NGX_OK; + } + + if (!rctx->initialized) { + + rctx->initialized = 1; + rctx->epoch = h->timestamp - rctx->time_shift; + + if (rctx->file.offset == 0 && + ngx_rtmp_record_write_header(&rctx->file) != NGX_OK) + { + ngx_rtmp_record_node_close(s, rctx); + return NGX_OK; + } + } + + codec_ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + if (codec_ctx) { + ch = *h; + + /* AAC header */ + if (!rctx->aac_header_sent && codec_ctx->aac_header && + (rracf->flags & NGX_RTMP_RECORD_AUDIO)) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V writing AAC header", &rracf->id); + + ch.type = NGX_RTMP_MSG_AUDIO; + ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->aac_header); + + if (ngx_rtmp_record_write_frame(s, rctx, &ch, + codec_ctx->aac_header, 0) + != NGX_OK) + { + return NGX_OK; + } + + rctx->aac_header_sent = 1; + } + + /* AVC header */ + if (!rctx->avc_header_sent && codec_ctx->avc_header && + (rracf->flags & (NGX_RTMP_RECORD_VIDEO| + NGX_RTMP_RECORD_KEYFRAMES))) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V writing AVC header", &rracf->id); + + ch.type = NGX_RTMP_MSG_VIDEO; + ch.mlen = ngx_rtmp_record_get_chain_mlen(codec_ctx->avc_header); + + if (ngx_rtmp_record_write_frame(s, rctx, &ch, + codec_ctx->avc_header, 0) + != NGX_OK) + { + return NGX_OK; + } + + rctx->avc_header_sent = 1; + } + } + + if (h->type == NGX_RTMP_MSG_VIDEO) { + if (codec_ctx && codec_ctx->video_codec_id == NGX_RTMP_VIDEO_H264 && + !rctx->avc_header_sent) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V skipping until H264 header", &rracf->id); + return NGX_OK; + } + + if (ngx_rtmp_get_video_frame_type(in) == NGX_RTMP_VIDEO_KEY_FRAME && + ((codec_ctx && codec_ctx->video_codec_id != NGX_RTMP_VIDEO_H264) || + !ngx_rtmp_is_codec_header(in))) + { + rctx->video_key_sent = 1; + } + + if (!rctx->video_key_sent) { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V skipping until keyframe", &rracf->id); + return NGX_OK; + } + + } else { + if (codec_ctx && codec_ctx->audio_codec_id == NGX_RTMP_AUDIO_AAC && + !rctx->aac_header_sent) + { + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "record: %V skipping until AAC header", &rracf->id); + return NGX_OK; + } + } + + return ngx_rtmp_record_write_frame(s, rctx, h, in, 1); +} + + +static ngx_int_t +ngx_rtmp_record_done_init(ngx_rtmp_session_t *s, ngx_rtmp_record_done_t *v) +{ + return NGX_OK; +} + + +static char * +ngx_rtmp_record_recorder(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + ngx_int_t i; + ngx_str_t *value; + ngx_conf_t save; + ngx_module_t **modules; + ngx_rtmp_module_t *module; + ngx_rtmp_core_app_conf_t *cacf, **pcacf, *rcacf; + ngx_rtmp_record_app_conf_t *racf, **pracf, *rracf; + ngx_rtmp_conf_ctx_t *ctx, *pctx; + + value = cf->args->elts; + + cacf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_core_module); + + racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_record_module); + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + pctx = cf->ctx; + + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ctx->app_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_rtmp_max_module); + if (ctx->app_conf == NULL) { + return NGX_CONF_ERROR; + } + +#if (nginx_version >= 1009011) + modules = cf->cycle->modules; +#else + modules = ngx_modules; +#endif + + for (i = 0; modules[i]; i++) { + if (modules[i]->type != NGX_RTMP_MODULE) { + continue; + } + + module = modules[i]->ctx; + + if (module->create_app_conf) { + ctx->app_conf[modules[i]->ctx_index] = module->create_app_conf(cf); + if (ctx->app_conf[modules[i]->ctx_index] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + /* add to sub-applications */ + rcacf = ctx->app_conf[ngx_rtmp_core_module.ctx_index]; + rcacf->app_conf = ctx->app_conf; + pcacf = ngx_array_push(&cacf->applications); + if (pcacf == NULL) { + return NGX_CONF_ERROR; + } + *pcacf = rcacf; + + /* add to recorders */ + rracf = ctx->app_conf[ngx_rtmp_record_module.ctx_index]; + rracf->rec_conf = ctx->app_conf; + pracf = ngx_array_push(&racf->rec); + if (pracf == NULL) { + return NGX_CONF_ERROR; + } + *pracf = rracf; + + rracf->id = value[1]; + + + save = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_RTMP_REC_CONF; + + rv = ngx_conf_parse(cf, NULL); + *cf= save; + + return rv; +} + + +static ngx_int_t +ngx_rtmp_record_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + + ngx_rtmp_record_done = ngx_rtmp_record_done_init; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_AUDIO]); + *h = ngx_rtmp_record_av; + + h = ngx_array_push(&cmcf->events[NGX_RTMP_MSG_VIDEO]); + *h = ngx_rtmp_record_av; + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_record_publish; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_record_close_stream; + + next_stream_begin = ngx_rtmp_stream_begin; + ngx_rtmp_stream_begin = ngx_rtmp_record_stream_begin; + + next_stream_eof = ngx_rtmp_stream_eof; + ngx_rtmp_stream_eof = ngx_rtmp_record_stream_eof; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_record_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_record_module.h new file mode 100644 index 0000000..6450dcb --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_record_module.h @@ -0,0 +1,96 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_RECORD_H_INCLUDED_ +#define _NGX_RTMP_RECORD_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +#define NGX_RTMP_RECORD_OFF 0x01 +#define NGX_RTMP_RECORD_AUDIO 0x02 +#define NGX_RTMP_RECORD_VIDEO 0x04 +#define NGX_RTMP_RECORD_KEYFRAMES 0x08 +#define NGX_RTMP_RECORD_MANUAL 0x10 + + +typedef struct { + ngx_str_t id; + ngx_uint_t flags; + ngx_str_t path; + size_t max_size; + size_t max_frames; + ngx_msec_t interval; + ngx_str_t suffix; + ngx_flag_t unique; + ngx_flag_t append; + ngx_flag_t lock_file; + ngx_flag_t notify; + ngx_url_t *url; + + void **rec_conf; + ngx_array_t rec; /* ngx_rtmp_record_app_conf_t * */ +} ngx_rtmp_record_app_conf_t; + + +typedef struct { + ngx_rtmp_record_app_conf_t *conf; + ngx_file_t file; + ngx_uint_t nframes; + uint32_t epoch, time_shift; + ngx_time_t last; + time_t timestamp; + unsigned failed:1; + unsigned initialized:1; + unsigned aac_header_sent:1; + unsigned avc_header_sent:1; + unsigned video_key_sent:1; + unsigned audio:1; + unsigned video:1; +} ngx_rtmp_record_rec_ctx_t; + + +typedef struct { + ngx_array_t rec; /* ngx_rtmp_record_rec_ctx_t */ + u_char name[NGX_RTMP_MAX_NAME]; + u_char args[NGX_RTMP_MAX_ARGS]; +} ngx_rtmp_record_ctx_t; + + +ngx_uint_t ngx_rtmp_record_find(ngx_rtmp_record_app_conf_t *racf, + ngx_str_t *id); + + +/* Manual recording control, + * 'n' is record node index in config array. + * Note: these functions allocate path in static buffer */ + +ngx_int_t ngx_rtmp_record_open(ngx_rtmp_session_t *s, ngx_uint_t n, + ngx_str_t *path); +ngx_int_t ngx_rtmp_record_close(ngx_rtmp_session_t *s, ngx_uint_t n, + ngx_str_t *path); + + +typedef struct { + ngx_str_t recorder; + ngx_str_t path; +} ngx_rtmp_record_done_t; + + +typedef ngx_int_t (*ngx_rtmp_record_done_pt)(ngx_rtmp_session_t *s, + ngx_rtmp_record_done_t *v); + + +extern ngx_rtmp_record_done_pt ngx_rtmp_record_done; + + +extern ngx_module_t ngx_rtmp_record_module; + + +#endif /* _NGX_RTMP_RECORD_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c new file mode 100644 index 0000000..b0f5fec --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c @@ -0,0 +1,1690 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp_relay_module.h" +#include "ngx_rtmp_cmd_module.h" + + +static ngx_rtmp_publish_pt next_publish; +static ngx_rtmp_play_pt next_play; +static ngx_rtmp_delete_stream_pt next_delete_stream; +static ngx_rtmp_close_stream_pt next_close_stream; + + +static ngx_int_t ngx_rtmp_relay_init_process(ngx_cycle_t *cycle); +static ngx_int_t ngx_rtmp_relay_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_relay_create_app_conf(ngx_conf_t *cf); +static char * ngx_rtmp_relay_merge_app_conf(ngx_conf_t *cf, + void *parent, void *child); +static char * ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_rtmp_relay_publish(ngx_rtmp_session_t *s, + ngx_rtmp_publish_t *v); +static ngx_rtmp_relay_ctx_t * ngx_rtmp_relay_create_connection( + ngx_rtmp_conf_ctx_t *cctx, ngx_str_t* name, + ngx_rtmp_relay_target_t *target); + + +/* _____ + * =push= | |---publish---> + * ---publish--->| |---publish---> + * (src) | |---publish---> + * ----- (next,relay) + * need reconnect + * =pull= _____ + * -----play---->| | + * -----play---->| |----play-----> + * -----play---->| | (src,relay) + * (next) ----- + */ + + +typedef struct { + ngx_array_t pulls; /* ngx_rtmp_relay_target_t * */ + ngx_array_t pushes; /* ngx_rtmp_relay_target_t * */ + ngx_array_t static_pulls; /* ngx_rtmp_relay_target_t * */ + ngx_array_t static_events; /* ngx_event_t * */ + ngx_log_t *log; + ngx_uint_t nbuckets; + ngx_msec_t buflen; + ngx_flag_t session_relay; + ngx_msec_t push_reconnect; + ngx_msec_t pull_reconnect; + ngx_rtmp_relay_ctx_t **ctx; +} ngx_rtmp_relay_app_conf_t; + + +typedef struct { + ngx_rtmp_conf_ctx_t cctx; + ngx_rtmp_relay_target_t *target; +} ngx_rtmp_relay_static_t; + + +#define NGX_RTMP_RELAY_CONNECT_TRANS 1 +#define NGX_RTMP_RELAY_CREATE_STREAM_TRANS 2 + + +#define NGX_RTMP_RELAY_CSID_AMF_INI 3 +#define NGX_RTMP_RELAY_CSID_AMF 5 +#define NGX_RTMP_RELAY_MSID 1 + + +/* default flashVer */ +#define NGX_RTMP_RELAY_FLASHVER "LNX.11,1,102,55" + + +static ngx_command_t ngx_rtmp_relay_commands[] = { + + { ngx_string("push"), + NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_relay_push_pull, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("pull"), + NGX_RTMP_APP_CONF|NGX_CONF_1MORE, + ngx_rtmp_relay_push_pull, + NGX_RTMP_APP_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("relay_buffer"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_relay_app_conf_t, buflen), + NULL }, + + { ngx_string("push_reconnect"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_relay_app_conf_t, push_reconnect), + NULL }, + + { ngx_string("pull_reconnect"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_relay_app_conf_t, pull_reconnect), + NULL }, + + { ngx_string("session_relay"), + NGX_RTMP_MAIN_CONF|NGX_RTMP_SRV_CONF|NGX_RTMP_APP_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_RTMP_APP_CONF_OFFSET, + offsetof(ngx_rtmp_relay_app_conf_t, session_relay), + NULL }, + + + ngx_null_command +}; + + +static ngx_rtmp_module_t ngx_rtmp_relay_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_relay_postconfiguration, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + ngx_rtmp_relay_create_app_conf, /* create app configuration */ + ngx_rtmp_relay_merge_app_conf /* merge app configuration */ +}; + + +ngx_module_t ngx_rtmp_relay_module = { + NGX_MODULE_V1, + &ngx_rtmp_relay_module_ctx, /* module context */ + ngx_rtmp_relay_commands, /* module directives */ + NGX_RTMP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_rtmp_relay_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static void * +ngx_rtmp_relay_create_app_conf(ngx_conf_t *cf) +{ + ngx_rtmp_relay_app_conf_t *racf; + + racf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_relay_app_conf_t)); + if (racf == NULL) { + return NULL; + } + + if (ngx_array_init(&racf->pushes, cf->pool, 1, sizeof(void *)) != NGX_OK) { + return NULL; + } + + if (ngx_array_init(&racf->pulls, cf->pool, 1, sizeof(void *)) != NGX_OK) { + return NULL; + } + + if (ngx_array_init(&racf->static_pulls, cf->pool, 1, sizeof(void *)) + != NGX_OK) + { + return NULL; + } + + if (ngx_array_init(&racf->static_events, cf->pool, 1, sizeof(void *)) + != NGX_OK) + { + return NULL; + } + + racf->nbuckets = 1024; + racf->log = &cf->cycle->new_log; + racf->buflen = NGX_CONF_UNSET_MSEC; + racf->session_relay = NGX_CONF_UNSET; + racf->push_reconnect = NGX_CONF_UNSET_MSEC; + racf->pull_reconnect = NGX_CONF_UNSET_MSEC; + + return racf; +} + + +static char * +ngx_rtmp_relay_merge_app_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_relay_app_conf_t *prev = parent; + ngx_rtmp_relay_app_conf_t *conf = child; + + conf->ctx = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_relay_ctx_t *) + * conf->nbuckets); + + ngx_conf_merge_value(conf->session_relay, prev->session_relay, 0); + ngx_conf_merge_msec_value(conf->buflen, prev->buflen, 5000); + ngx_conf_merge_msec_value(conf->push_reconnect, prev->push_reconnect, + 3000); + ngx_conf_merge_msec_value(conf->pull_reconnect, prev->pull_reconnect, + 3000); + + return NGX_CONF_OK; +} + + +static void +ngx_rtmp_relay_static_pull_reconnect(ngx_event_t *ev) +{ + ngx_rtmp_relay_static_t *rs = ev->data; + + ngx_rtmp_relay_ctx_t *ctx; + ngx_rtmp_relay_app_conf_t *racf; + + racf = ngx_rtmp_get_module_app_conf(&rs->cctx, ngx_rtmp_relay_module); + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, racf->log, 0, + "relay: reconnecting static pull"); + + ctx = ngx_rtmp_relay_create_connection(&rs->cctx, &rs->target->name, + rs->target); + if (ctx) { + ctx->session->static_relay = 1; + ctx->static_evt = ev; + return; + } + + ngx_add_timer(ev, racf->pull_reconnect); +} + + +static void +ngx_rtmp_relay_push_reconnect(ngx_event_t *ev) +{ + ngx_rtmp_session_t *s = ev->data; + + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_ctx_t *ctx, *pctx; + ngx_uint_t n; + ngx_rtmp_relay_target_t *target, **t; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: push reconnect"); + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + return; + } + + t = racf->pushes.elts; + for (n = 0; n < racf->pushes.nelts; ++n, ++t) { + target = *t; + + if (target->name.len && (ctx->name.len != target->name.len || + ngx_memcmp(ctx->name.data, target->name.data, ctx->name.len))) + { + continue; + } + + for (pctx = ctx->play; pctx; pctx = pctx->next) { + if (pctx->tag == &ngx_rtmp_relay_module && + pctx->data == target) + { + break; + } + } + + if (pctx) { + continue; + } + + if (ngx_rtmp_relay_push(s, &ctx->name, target) == NGX_OK) { + continue; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "relay: push reconnect failed name='%V' app='%V' " + "playpath='%V' url='%V'", + &ctx->name, &target->app, &target->play_path, + &target->url.url); + + if (!ctx->push_evt.timer_set) { + ngx_add_timer(&ctx->push_evt, racf->push_reconnect); + } + } +} + + +static ngx_int_t +ngx_rtmp_relay_get_peer(ngx_peer_connection_t *pc, void *data) +{ + return NGX_OK; +} + + +static void +ngx_rtmp_relay_free_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state) +{ +} + + +typedef ngx_rtmp_relay_ctx_t * (* ngx_rtmp_relay_create_ctx_pt) + (ngx_rtmp_session_t *s, ngx_str_t *name, ngx_rtmp_relay_target_t *target); + + +static ngx_int_t +ngx_rtmp_relay_copy_str(ngx_pool_t *pool, ngx_str_t *dst, ngx_str_t *src) +{ + if (src->len == 0) { + return NGX_OK; + } + dst->len = src->len; + dst->data = ngx_palloc(pool, src->len); + if (dst->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(dst->data, src->data, src->len); + return NGX_OK; +} + + +static ngx_rtmp_relay_ctx_t * +ngx_rtmp_relay_create_connection(ngx_rtmp_conf_ctx_t *cctx, ngx_str_t* name, + ngx_rtmp_relay_target_t *target) +{ + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_ctx_t *rctx; + ngx_rtmp_addr_conf_t *addr_conf; + ngx_rtmp_conf_ctx_t *addr_ctx; + ngx_rtmp_session_t *rs; + ngx_peer_connection_t *pc; + ngx_connection_t *c; + ngx_addr_t *addr; + ngx_pool_t *pool; + ngx_int_t rc; + ngx_str_t v, *uri; + u_char *first, *last, *p; + + racf = ngx_rtmp_get_module_app_conf(cctx, ngx_rtmp_relay_module); + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, racf->log, 0, + "relay: create remote context"); + + pool = NULL; + pool = ngx_create_pool(4096, racf->log); + if (pool == NULL) { + return NULL; + } + + rctx = ngx_pcalloc(pool, sizeof(ngx_rtmp_relay_ctx_t)); + if (rctx == NULL) { + goto clear; + } + + if (name && ngx_rtmp_relay_copy_str(pool, &rctx->name, name) != NGX_OK) { + goto clear; + } + + if (ngx_rtmp_relay_copy_str(pool, &rctx->url, &target->url.url) != NGX_OK) { + goto clear; + } + + rctx->tag = target->tag; + rctx->data = target->data; + +#define NGX_RTMP_RELAY_STR_COPY(to, from) \ + if (ngx_rtmp_relay_copy_str(pool, &rctx->to, &target->from) != NGX_OK) { \ + goto clear; \ + } + + NGX_RTMP_RELAY_STR_COPY(app, app); + NGX_RTMP_RELAY_STR_COPY(tc_url, tc_url); + NGX_RTMP_RELAY_STR_COPY(page_url, page_url); + NGX_RTMP_RELAY_STR_COPY(swf_url, swf_url); + NGX_RTMP_RELAY_STR_COPY(flash_ver, flash_ver); + NGX_RTMP_RELAY_STR_COPY(play_path, play_path); + + rctx->live = target->live; + rctx->start = target->start; + rctx->stop = target->stop; + +#undef NGX_RTMP_RELAY_STR_COPY + + if (rctx->app.len == 0 || rctx->play_path.len == 0) { + /* parse uri */ + uri = &target->url.uri; + first = uri->data; + last = uri->data + uri->len; + if (first != last && *first == '/') { + ++first; + } + + if (first != last) { + + /* deduce app */ + p = ngx_strlchr(first, last, '/'); + if (p == NULL) { + p = last; + } + + if (rctx->app.len == 0 && first != p) { + v.data = first; + v.len = p - first; + if (ngx_rtmp_relay_copy_str(pool, &rctx->app, &v) != NGX_OK) { + goto clear; + } + } + + /* deduce play_path */ + if (p != last) { + ++p; + } + + if (rctx->play_path.len == 0 && p != last) { + v.data = p; + v.len = last - p; + if (ngx_rtmp_relay_copy_str(pool, &rctx->play_path, &v) + != NGX_OK) + { + goto clear; + } + } + } + } + + pc = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t)); + if (pc == NULL) { + goto clear; + } + + if (target->url.naddrs == 0) { + ngx_log_error(NGX_LOG_ERR, racf->log, 0, + "relay: no address"); + goto clear; + } + + /* get address */ + addr = &target->url.addrs[target->counter % target->url.naddrs]; + target->counter++; + + /* copy log to keep shared log unchanged */ + rctx->log = *racf->log; + pc->log = &rctx->log; + pc->get = ngx_rtmp_relay_get_peer; + pc->free = ngx_rtmp_relay_free_peer; + pc->name = &addr->name; + pc->socklen = addr->socklen; + pc->sockaddr = (struct sockaddr *)ngx_palloc(pool, pc->socklen); + if (pc->sockaddr == NULL) { + goto clear; + } + ngx_memcpy(pc->sockaddr, addr->sockaddr, pc->socklen); + + rc = ngx_event_connect_peer(pc); + if (rc != NGX_OK && rc != NGX_AGAIN ) { + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, racf->log, 0, + "relay: connection failed"); + goto clear; + } + c = pc->connection; + c->pool = pool; + c->addr_text = rctx->url; + + addr_conf = ngx_pcalloc(pool, sizeof(ngx_rtmp_addr_conf_t)); + if (addr_conf == NULL) { + goto clear; + } + addr_ctx = ngx_pcalloc(pool, sizeof(ngx_rtmp_conf_ctx_t)); + if (addr_ctx == NULL) { + goto clear; + } + addr_conf->ctx = addr_ctx; + addr_ctx->main_conf = cctx->main_conf; + addr_ctx->srv_conf = cctx->srv_conf; + ngx_str_set(&addr_conf->addr_text, "ngx-relay"); + + rs = ngx_rtmp_init_session(c, addr_conf); + if (rs == NULL) { + /* no need to destroy pool */ + return NULL; + } + rs->app_conf = cctx->app_conf; + rs->relay = 1; + rctx->session = rs; + ngx_rtmp_set_ctx(rs, rctx, ngx_rtmp_relay_module); + ngx_str_set(&rs->flashver, "ngx-local-relay"); + +#if (NGX_STAT_STUB) + (void) ngx_atomic_fetch_add(ngx_stat_active, 1); +#endif + + ngx_rtmp_client_handshake(rs, 1); + return rctx; + +clear: + if (pool) { + ngx_destroy_pool(pool); + } + return NULL; +} + + +static ngx_rtmp_relay_ctx_t * +ngx_rtmp_relay_create_remote_ctx(ngx_rtmp_session_t *s, ngx_str_t* name, + ngx_rtmp_relay_target_t *target) +{ + ngx_rtmp_conf_ctx_t cctx; + + cctx.app_conf = s->app_conf; + cctx.srv_conf = s->srv_conf; + cctx.main_conf = s->main_conf; + + return ngx_rtmp_relay_create_connection(&cctx, name, target); +} + + +static ngx_rtmp_relay_ctx_t * +ngx_rtmp_relay_create_local_ctx(ngx_rtmp_session_t *s, ngx_str_t *name, + ngx_rtmp_relay_target_t *target) +{ + ngx_rtmp_relay_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: create local context"); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_rtmp_relay_ctx_t)); + if (ctx == NULL) { + return NULL; + } + ngx_rtmp_set_ctx(s, ctx, ngx_rtmp_relay_module); + } + ctx->session = s; + + ctx->push_evt.data = s; + ctx->push_evt.log = s->connection->log; + ctx->push_evt.handler = ngx_rtmp_relay_push_reconnect; + + if (ctx->publish) { + return NULL; + } + + if (ngx_rtmp_relay_copy_str(s->connection->pool, &ctx->name, name) + != NGX_OK) + { + return NULL; + } + + return ctx; +} + + +static ngx_int_t +ngx_rtmp_relay_create(ngx_rtmp_session_t *s, ngx_str_t *name, + ngx_rtmp_relay_target_t *target, + ngx_rtmp_relay_create_ctx_pt create_publish_ctx, + ngx_rtmp_relay_create_ctx_pt create_play_ctx) +{ + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_ctx_t *publish_ctx, *play_ctx, **cctx; + ngx_uint_t hash; + + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + if (racf == NULL) { + return NGX_ERROR; + } + + play_ctx = create_play_ctx(s, name, target); + if (play_ctx == NULL) { + return NGX_ERROR; + } + + hash = ngx_hash_key(name->data, name->len); + cctx = &racf->ctx[hash % racf->nbuckets]; + for (; *cctx; cctx = &(*cctx)->next) { + if ((*cctx)->name.len == name->len + && !ngx_memcmp(name->data, (*cctx)->name.data, + name->len)) + { + break; + } + } + + if (*cctx) { + play_ctx->publish = (*cctx)->publish; + play_ctx->next = (*cctx)->play; + (*cctx)->play = play_ctx; + return NGX_OK; + } + + publish_ctx = create_publish_ctx(s, name, target); + if (publish_ctx == NULL) { + ngx_rtmp_finalize_session(play_ctx->session); + return NGX_ERROR; + } + + publish_ctx->publish = publish_ctx; + publish_ctx->play = play_ctx; + play_ctx->publish = publish_ctx; + *cctx = publish_ctx; + + return NGX_OK; +} + + +ngx_int_t +ngx_rtmp_relay_pull(ngx_rtmp_session_t *s, ngx_str_t *name, + ngx_rtmp_relay_target_t *target) +{ + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "relay: create pull name='%V' app='%V' playpath='%V' url='%V'", + name, &target->app, &target->play_path, &target->url.url); + + return ngx_rtmp_relay_create(s, name, target, + ngx_rtmp_relay_create_remote_ctx, + ngx_rtmp_relay_create_local_ctx); +} + + +ngx_int_t +ngx_rtmp_relay_push(ngx_rtmp_session_t *s, ngx_str_t *name, + ngx_rtmp_relay_target_t *target) +{ + ngx_log_error(NGX_LOG_INFO, s->connection->log, 0, + "relay: create push name='%V' app='%V' playpath='%V' url='%V'", + name, &target->app, &target->play_path, &target->url.url); + + return ngx_rtmp_relay_create(s, name, target, + ngx_rtmp_relay_create_local_ctx, + ngx_rtmp_relay_create_remote_ctx); +} + + +static ngx_int_t +ngx_rtmp_relay_publish(ngx_rtmp_session_t *s, ngx_rtmp_publish_t *v) +{ + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_target_t *target, **t; + ngx_str_t name; + size_t n; + ngx_rtmp_relay_ctx_t *ctx; + + if (s->auto_pushed) { + goto next; + } + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx && s->relay) { + goto next; + } + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + if (racf == NULL || racf->pushes.nelts == 0) { + goto next; + } + + name.len = ngx_strlen(v->name); + name.data = v->name; + + t = racf->pushes.elts; + for (n = 0; n < racf->pushes.nelts; ++n, ++t) { + target = *t; + + if (target->name.len && (name.len != target->name.len || + ngx_memcmp(name.data, target->name.data, name.len))) + { + continue; + } + + if (ngx_rtmp_relay_push(s, &name, target) == NGX_OK) { + continue; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "relay: push failed name='%V' app='%V' " + "playpath='%V' url='%V'", + &name, &target->app, &target->play_path, + &target->url.url); + + if (!ctx->push_evt.timer_set) { + ngx_add_timer(&ctx->push_evt, racf->push_reconnect); + } + } + +next: + return next_publish(s, v); +} + + +static ngx_int_t +ngx_rtmp_relay_play(ngx_rtmp_session_t *s, ngx_rtmp_play_t *v) +{ + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_target_t *target, **t; + ngx_str_t name; + size_t n; + ngx_rtmp_relay_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx && s->relay) { + goto next; + } + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + if (racf == NULL || racf->pulls.nelts == 0) { + goto next; + } + + name.len = ngx_strlen(v->name); + name.data = v->name; + + t = racf->pulls.elts; + for (n = 0; n < racf->pulls.nelts; ++n, ++t) { + target = *t; + + if (target->name.len && (name.len != target->name.len || + ngx_memcmp(name.data, target->name.data, name.len))) + { + continue; + } + + if (ngx_rtmp_relay_pull(s, &name, target) == NGX_OK) { + continue; + } + + ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, + "relay: pull failed name='%V' app='%V' " + "playpath='%V' url='%V'", + &name, &target->app, &target->play_path, + &target->url.url); + } + +next: + return next_play(s, v); +} + + +static ngx_int_t +ngx_rtmp_relay_play_local(ngx_rtmp_session_t *s) +{ + ngx_rtmp_play_t v; + ngx_rtmp_relay_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&v, sizeof(ngx_rtmp_play_t)); + v.silent = 1; + *(ngx_cpymem(v.name, ctx->name.data, + ngx_min(sizeof(v.name) - 1, ctx->name.len))) = 0; + + return ngx_rtmp_play(s, &v); +} + + +static ngx_int_t +ngx_rtmp_relay_publish_local(ngx_rtmp_session_t *s) +{ + ngx_rtmp_publish_t v; + ngx_rtmp_relay_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_memzero(&v, sizeof(ngx_rtmp_publish_t)); + v.silent = 1; + *(ngx_cpymem(v.name, ctx->name.data, + ngx_min(sizeof(v.name) - 1, ctx->name.len))) = 0; + + return ngx_rtmp_publish(s, &v); +} + + +static ngx_int_t +ngx_rtmp_relay_send_connect(ngx_rtmp_session_t *s) +{ + static double trans = NGX_RTMP_RELAY_CONNECT_TRANS; + static double acodecs = 3575; + static double vcodecs = 252; + + static ngx_rtmp_amf_elt_t out_cmd[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("app"), + NULL, 0 }, /* <-- fill */ + + { NGX_RTMP_AMF_STRING, + ngx_string("tcUrl"), + NULL, 0 }, /* <-- fill */ + + { NGX_RTMP_AMF_STRING, + ngx_string("pageUrl"), + NULL, 0 }, /* <-- fill */ + + { NGX_RTMP_AMF_STRING, + ngx_string("swfUrl"), + NULL, 0 }, /* <-- fill */ + + { NGX_RTMP_AMF_STRING, + ngx_string("flashVer"), + NULL, 0 }, /* <-- fill */ + + { NGX_RTMP_AMF_NUMBER, + ngx_string("audioCodecs"), + &acodecs, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("videoCodecs"), + &vcodecs, 0 } + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "connect", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_cmd, sizeof(out_cmd) } + }; + + ngx_rtmp_core_app_conf_t *cacf; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_rtmp_relay_ctx_t *ctx; + ngx_rtmp_header_t h; + size_t len, url_len; + u_char *p, *url_end; + + + cacf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_core_module); + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (cacf == NULL || ctx == NULL) { + return NGX_ERROR; + } + + /* app */ + if (ctx->app.len) { + out_cmd[0].data = ctx->app.data; + out_cmd[0].len = ctx->app.len; + } else { + out_cmd[0].data = cacf->name.data; + out_cmd[0].len = cacf->name.len; + } + + /* tcUrl */ + if (ctx->tc_url.len) { + out_cmd[1].data = ctx->tc_url.data; + out_cmd[1].len = ctx->tc_url.len; + } else { + len = sizeof("rtmp://") - 1 + ctx->url.len + + sizeof("/") - 1 + ctx->app.len; + p = ngx_palloc(s->connection->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + out_cmd[1].data = p; + p = ngx_cpymem(p, "rtmp://", sizeof("rtmp://") - 1); + + url_len = ctx->url.len; + url_end = ngx_strlchr(ctx->url.data, ctx->url.data + ctx->url.len, '/'); + if (url_end) { + url_len = (size_t) (url_end - ctx->url.data); + } + + p = ngx_cpymem(p, ctx->url.data, url_len); + *p++ = '/'; + p = ngx_cpymem(p, ctx->app.data, ctx->app.len); + out_cmd[1].len = p - (u_char *)out_cmd[1].data; + } + + /* pageUrl */ + out_cmd[2].data = ctx->page_url.data; + out_cmd[2].len = ctx->page_url.len; + + /* swfUrl */ + out_cmd[3].data = ctx->swf_url.data; + out_cmd[3].len = ctx->swf_url.len; + + /* flashVer */ + if (ctx->flash_ver.len) { + out_cmd[4].data = ctx->flash_ver.data; + out_cmd[4].len = ctx->flash_ver.len; + } else { + out_cmd[4].data = NGX_RTMP_RELAY_FLASHVER; + out_cmd[4].len = sizeof(NGX_RTMP_RELAY_FLASHVER) - 1; + } + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_RELAY_CSID_AMF_INI; + h.type = NGX_RTMP_MSG_AMF_CMD; + + return ngx_rtmp_send_chunk_size(s, cscf->chunk_size) != NGX_OK + || ngx_rtmp_send_ack_size(s, cscf->ack_window) != NGX_OK + || ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK + ? NGX_ERROR + : NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_relay_send_create_stream(ngx_rtmp_session_t *s) +{ + static double trans = NGX_RTMP_RELAY_CREATE_STREAM_TRANS; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "createStream", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 } + }; + + ngx_rtmp_header_t h; + + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_RELAY_CSID_AMF_INI; + h.type = NGX_RTMP_MSG_AMF_CMD; + + return ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} + + +static ngx_int_t +ngx_rtmp_relay_send_publish(ngx_rtmp_session_t *s) +{ + static double trans; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "publish", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + NULL, 0 }, /* <- to fill */ + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "live", 0 } + }; + + ngx_rtmp_header_t h; + ngx_rtmp_relay_ctx_t *ctx; + + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ctx->play_path.len) { + out_elts[3].data = ctx->play_path.data; + out_elts[3].len = ctx->play_path.len; + } else { + out_elts[3].data = ctx->name.data; + out_elts[3].len = ctx->name.len; + } + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_RELAY_CSID_AMF; + h.msid = NGX_RTMP_RELAY_MSID; + h.type = NGX_RTMP_MSG_AMF_CMD; + + return ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} + + +static ngx_int_t +ngx_rtmp_relay_send_play(ngx_rtmp_session_t *s) +{ + static double trans; + static double start, duration; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "play", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + NULL, 0 }, /* <- fill */ + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &start, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &duration, 0 }, + }; + + ngx_rtmp_header_t h; + ngx_rtmp_relay_ctx_t *ctx; + ngx_rtmp_relay_app_conf_t *racf; + + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (racf == NULL || ctx == NULL) { + return NGX_ERROR; + } + + if (ctx->play_path.len) { + out_elts[3].data = ctx->play_path.data; + out_elts[3].len = ctx->play_path.len; + } else { + out_elts[3].data = ctx->name.data; + out_elts[3].len = ctx->name.len; + } + + if (ctx->live) { + start = -1000; + duration = -1000; + } else { + start = (ctx->start ? ctx->start : -2000); + duration = (ctx->stop ? ctx->stop - ctx->start : -1000); + } + + ngx_memzero(&h, sizeof(h)); + h.csid = NGX_RTMP_RELAY_CSID_AMF; + h.msid = NGX_RTMP_RELAY_MSID; + h.type = NGX_RTMP_MSG_AMF_CMD; + + return ngx_rtmp_send_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])) != NGX_OK + || ngx_rtmp_send_set_buflen(s, NGX_RTMP_RELAY_MSID, + racf->buflen) != NGX_OK + ? NGX_ERROR + : NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_relay_on_result(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_relay_ctx_t *ctx; + static struct { + double trans; + u_char level[32]; + u_char code[128]; + u_char desc[1024]; + } v; + + static ngx_rtmp_amf_elt_t in_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + &v.level, sizeof(v.level) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("code"), + &v.code, sizeof(v.code) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("description"), + &v.desc, sizeof(v.desc) }, + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL || !s->relay) { + return NGX_OK; + } + + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: _result: level='%s' code='%s' description='%s'", + v.level, v.code, v.desc); + + switch ((ngx_int_t)v.trans) { + case NGX_RTMP_RELAY_CONNECT_TRANS: + return ngx_rtmp_relay_send_create_stream(s); + + case NGX_RTMP_RELAY_CREATE_STREAM_TRANS: + if (ctx->publish != ctx && !s->static_relay) { + if (ngx_rtmp_relay_send_publish(s) != NGX_OK) { + return NGX_ERROR; + } + return ngx_rtmp_relay_play_local(s); + + } else { + if (ngx_rtmp_relay_send_play(s) != NGX_OK) { + return NGX_ERROR; + } + return ngx_rtmp_relay_publish_local(s); + } + + default: + return NGX_OK; + } +} + + +static ngx_int_t +ngx_rtmp_relay_on_error(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_relay_ctx_t *ctx; + static struct { + double trans; + u_char level[32]; + u_char code[128]; + u_char desc[1024]; + } v; + + static ngx_rtmp_amf_elt_t in_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + &v.level, sizeof(v.level) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("code"), + &v.code, sizeof(v.code) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("description"), + &v.desc, sizeof(v.desc) }, + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL || !s->relay) { + return NGX_OK; + } + + ngx_memzero(&v, sizeof(v)); + if (ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0]))) + { + return NGX_ERROR; + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: _error: level='%s' code='%s' description='%s'", + v.level, v.code, v.desc); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_relay_on_status(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_relay_ctx_t *ctx; + static struct { + double trans; + u_char level[32]; + u_char code[128]; + u_char desc[1024]; + } v; + + static ngx_rtmp_amf_elt_t in_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + &v.level, sizeof(v.level) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("code"), + &v.code, sizeof(v.code) }, + + { NGX_RTMP_AMF_STRING, + ngx_string("description"), + &v.desc, sizeof(v.desc) }, + }; + + static ngx_rtmp_amf_elt_t in_elts[] = { + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &v.trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + static ngx_rtmp_amf_elt_t in_elts_meta[] = { + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + in_inf, sizeof(in_inf) }, + }; + + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL || !s->relay) { + return NGX_OK; + } + + ngx_memzero(&v, sizeof(v)); + if (h->type == NGX_RTMP_MSG_AMF_META) { + ngx_rtmp_receive_amf(s, in, in_elts_meta, + sizeof(in_elts_meta) / sizeof(in_elts_meta[0])); + } else { + ngx_rtmp_receive_amf(s, in, in_elts, + sizeof(in_elts) / sizeof(in_elts[0])); + } + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "relay: onStatus: level='%s' code='%s' description='%s'", + v.level, v.code, v.desc); + + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_relay_handshake_done(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_chain_t *in) +{ + ngx_rtmp_relay_ctx_t *ctx; + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL || !s->relay) { + return NGX_OK; + } + + return ngx_rtmp_relay_send_connect(s); +} + + +static void +ngx_rtmp_relay_close(ngx_rtmp_session_t *s) +{ + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_ctx_t *ctx, **cctx; + ngx_uint_t hash; + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + + ctx = ngx_rtmp_get_module_ctx(s, ngx_rtmp_relay_module); + if (ctx == NULL) { + return; + } + + if (s->static_relay) { + ngx_add_timer(ctx->static_evt, racf->pull_reconnect); + } + + if (ctx->publish == NULL) { + return; + } + + /* play end disconnect? */ + if (ctx->publish != ctx) { + for (cctx = &ctx->publish->play; *cctx; cctx = &(*cctx)->next) { + if (*cctx == ctx) { + *cctx = ctx->next; + break; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ctx->session->connection->log, 0, + "relay: play disconnect app='%V' name='%V'", + &ctx->app, &ctx->name); + + /* push reconnect */ + if (s->relay && ctx->tag == &ngx_rtmp_relay_module && + !ctx->publish->push_evt.timer_set) + { + ngx_add_timer(&ctx->publish->push_evt, racf->push_reconnect); + } + +#ifdef NGX_DEBUG + { + ngx_uint_t n = 0; + for (cctx = &ctx->publish->play; *cctx; cctx = &(*cctx)->next, ++n); + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, ctx->session->connection->log, 0, + "relay: play left after disconnect app='%V' name='%V': %ui", + &ctx->app, &ctx->name, n); + } +#endif + + if (ctx->publish->play == NULL && ctx->publish->session->relay) { + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, + ctx->publish->session->connection->log, 0, + "relay: publish disconnect empty app='%V' name='%V'", + &ctx->app, &ctx->name); + ngx_rtmp_finalize_session(ctx->publish->session); + } + + ctx->publish = NULL; + + return; + } + + /* publish end disconnect */ + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, ctx->session->connection->log, 0, + "relay: publish disconnect app='%V' name='%V'", + &ctx->app, &ctx->name); + + if (ctx->push_evt.timer_set) { + ngx_del_timer(&ctx->push_evt); + } + + for (cctx = &ctx->play; *cctx; cctx = &(*cctx)->next) { + (*cctx)->publish = NULL; + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, (*cctx)->session->connection->log, + 0, "relay: play disconnect orphan app='%V' name='%V'", + &(*cctx)->app, &(*cctx)->name); + ngx_rtmp_finalize_session((*cctx)->session); + } + ctx->publish = NULL; + + hash = ngx_hash_key(ctx->name.data, ctx->name.len); + cctx = &racf->ctx[hash % racf->nbuckets]; + for (; *cctx && *cctx != ctx; cctx = &(*cctx)->next); + if (*cctx) { + *cctx = ctx->next; + } +} + + +static ngx_int_t +ngx_rtmp_relay_close_stream(ngx_rtmp_session_t *s, ngx_rtmp_close_stream_t *v) +{ + ngx_rtmp_relay_app_conf_t *racf; + + racf = ngx_rtmp_get_module_app_conf(s, ngx_rtmp_relay_module); + if (racf && !racf->session_relay) { + ngx_rtmp_relay_close(s); + } + + return next_close_stream(s, v); +} + + +static ngx_int_t +ngx_rtmp_relay_delete_stream(ngx_rtmp_session_t *s, ngx_rtmp_delete_stream_t *v) +{ + ngx_rtmp_relay_close(s); + + return next_delete_stream(s, v); +} + + +static char * +ngx_rtmp_relay_push_pull(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_str_t *value, v, n; + ngx_rtmp_relay_app_conf_t *racf; + ngx_rtmp_relay_target_t *target, **t; + ngx_url_t *u; + ngx_uint_t i; + ngx_int_t is_pull, is_static; + ngx_event_t **ee, *e; + ngx_rtmp_relay_static_t *rs; + u_char *p; + + value = cf->args->elts; + + racf = ngx_rtmp_conf_get_module_app_conf(cf, ngx_rtmp_relay_module); + + is_pull = (value[0].data[3] == 'l'); + is_static = 0; + + target = ngx_pcalloc(cf->pool, sizeof(*target)); + if (target == NULL) { + return NGX_CONF_ERROR; + } + + target->tag = &ngx_rtmp_relay_module; + target->data = target; + + u = &target->url; + u->default_port = 1935; + u->uri_part = 1; + u->url = value[1]; + + if (ngx_strncasecmp(u->url.data, (u_char *) "rtmp://", 7) == 0) { + u->url.data += 7; + u->url.len -= 7; + } + + if (ngx_parse_url(cf->pool, u) != NGX_OK) { + if (u->err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in url \"%V\"", u->err, &u->url); + } + return NGX_CONF_ERROR; + } + + value += 2; + for (i = 2; i < cf->args->nelts; ++i, ++value) { + p = ngx_strlchr(value->data, value->data + value->len, '='); + + if (p == NULL) { + n = *value; + ngx_str_set(&v, "1"); + + } else { + n.data = value->data; + n.len = p - value->data; + + v.data = p + 1; + v.len = value->data + value->len - p - 1; + } + +#define NGX_RTMP_RELAY_STR_PAR(name, var) \ + if (n.len == sizeof(name) - 1 \ + && ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \ + { \ + target->var = v; \ + continue; \ + } + +#define NGX_RTMP_RELAY_NUM_PAR(name, var) \ + if (n.len == sizeof(name) - 1 \ + && ngx_strncasecmp(n.data, (u_char *) name, n.len) == 0) \ + { \ + target->var = ngx_atoi(v.data, v.len); \ + continue; \ + } + + NGX_RTMP_RELAY_STR_PAR("app", app); + NGX_RTMP_RELAY_STR_PAR("name", name); + NGX_RTMP_RELAY_STR_PAR("tcUrl", tc_url); + NGX_RTMP_RELAY_STR_PAR("pageUrl", page_url); + NGX_RTMP_RELAY_STR_PAR("swfUrl", swf_url); + NGX_RTMP_RELAY_STR_PAR("flashVer", flash_ver); + NGX_RTMP_RELAY_STR_PAR("playPath", play_path); + NGX_RTMP_RELAY_NUM_PAR("live", live); + NGX_RTMP_RELAY_NUM_PAR("start", start); + NGX_RTMP_RELAY_NUM_PAR("stop", stop); + +#undef NGX_RTMP_RELAY_STR_PAR +#undef NGX_RTMP_RELAY_NUM_PAR + + if (n.len == sizeof("static") - 1 && + ngx_strncasecmp(n.data, (u_char *) "static", n.len) == 0 && + ngx_atoi(v.data, v.len)) + { + is_static = 1; + continue; + } + + return "unsuppored parameter"; + } + + if (is_static) { + + if (!is_pull) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "static push is not allowed"); + return NGX_CONF_ERROR; + } + + if (target->name.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "stream name missing in static pull " + "declaration"); + return NGX_CONF_ERROR; + } + + ee = ngx_array_push(&racf->static_events); + if (ee == NULL) { + return NGX_CONF_ERROR; + } + + e = ngx_pcalloc(cf->pool, sizeof(ngx_event_t)); + if (e == NULL) { + return NGX_CONF_ERROR; + } + + *ee = e; + + rs = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_relay_static_t)); + if (rs == NULL) { + return NGX_CONF_ERROR; + } + + rs->target = target; + + e->data = rs; + e->log = &cf->cycle->new_log; + e->handler = ngx_rtmp_relay_static_pull_reconnect; + + t = ngx_array_push(&racf->static_pulls); + + } else if (is_pull) { + t = ngx_array_push(&racf->pulls); + + } else { + t = ngx_array_push(&racf->pushes); + } + + if (t == NULL) { + return NGX_CONF_ERROR; + } + + *t = target; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_rtmp_relay_init_process(ngx_cycle_t *cycle) +{ +#if !(NGX_WIN32) + ngx_rtmp_core_main_conf_t *cmcf = ngx_rtmp_core_main_conf; + ngx_rtmp_core_srv_conf_t **pcscf, *cscf; + ngx_rtmp_core_app_conf_t **pcacf, *cacf; + ngx_rtmp_relay_app_conf_t *racf; + ngx_uint_t n, m, k; + ngx_rtmp_relay_static_t *rs; + ngx_rtmp_listen_t *lst; + ngx_event_t **pevent, *event; + + if (cmcf == NULL || cmcf->listen.nelts == 0) { + return NGX_OK; + } + + /* only first worker does static pulling */ + + if (ngx_process_slot) { + return NGX_OK; + } + + lst = cmcf->listen.elts; + + pcscf = cmcf->servers.elts; + for (n = 0; n < cmcf->servers.nelts; ++n, ++pcscf) { + + cscf = *pcscf; + pcacf = cscf->applications.elts; + + for (m = 0; m < cscf->applications.nelts; ++m, ++pcacf) { + + cacf = *pcacf; + racf = cacf->app_conf[ngx_rtmp_relay_module.ctx_index]; + pevent = racf->static_events.elts; + + for (k = 0; k < racf->static_events.nelts; ++k, ++pevent) { + event = *pevent; + + rs = event->data; + rs->cctx = *lst->ctx; + rs->cctx.app_conf = cacf->app_conf; + + ngx_post_event(event, &ngx_rtmp_init_queue); + } + } + } +#endif + return NGX_OK; +} + + +static ngx_int_t +ngx_rtmp_relay_postconfiguration(ngx_conf_t *cf) +{ + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_handler_pt *h; + ngx_rtmp_amf_handler_t *ch; + + cmcf = ngx_rtmp_conf_get_module_main_conf(cf, ngx_rtmp_core_module); + + + h = ngx_array_push(&cmcf->events[NGX_RTMP_HANDSHAKE_DONE]); + *h = ngx_rtmp_relay_handshake_done; + + + next_publish = ngx_rtmp_publish; + ngx_rtmp_publish = ngx_rtmp_relay_publish; + + next_play = ngx_rtmp_play; + ngx_rtmp_play = ngx_rtmp_relay_play; + + next_delete_stream = ngx_rtmp_delete_stream; + ngx_rtmp_delete_stream = ngx_rtmp_relay_delete_stream; + + next_close_stream = ngx_rtmp_close_stream; + ngx_rtmp_close_stream = ngx_rtmp_relay_close_stream; + + + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "_result"); + ch->handler = ngx_rtmp_relay_on_result; + + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "_error"); + ch->handler = ngx_rtmp_relay_on_error; + + ch = ngx_array_push(&cmcf->amf); + ngx_str_set(&ch->name, "onStatus"); + ch->handler = ngx_rtmp_relay_on_status; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h b/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h new file mode 100644 index 0000000..d1baeae --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h @@ -0,0 +1,72 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_RELAY_H_INCLUDED_ +#define _NGX_RTMP_RELAY_H_INCLUDED_ + + +#include +#include +#include "ngx_rtmp.h" + + +typedef struct { + ngx_url_t url; + ngx_str_t app; + ngx_str_t name; + ngx_str_t tc_url; + ngx_str_t page_url; + ngx_str_t swf_url; + ngx_str_t flash_ver; + ngx_str_t play_path; + ngx_int_t live; + ngx_int_t start; + ngx_int_t stop; + + void *tag; /* usually module reference */ + void *data; /* module-specific data */ + ngx_uint_t counter; /* mutable connection counter */ +} ngx_rtmp_relay_target_t; + + +typedef struct ngx_rtmp_relay_ctx_s ngx_rtmp_relay_ctx_t; + +struct ngx_rtmp_relay_ctx_s { + ngx_str_t name; + ngx_str_t url; + ngx_log_t log; + ngx_rtmp_session_t *session; + ngx_rtmp_relay_ctx_t *publish; + ngx_rtmp_relay_ctx_t *play; + ngx_rtmp_relay_ctx_t *next; + + ngx_str_t app; + ngx_str_t tc_url; + ngx_str_t page_url; + ngx_str_t swf_url; + ngx_str_t flash_ver; + ngx_str_t play_path; + ngx_int_t live; + ngx_int_t start; + ngx_int_t stop; + + ngx_event_t push_evt; + ngx_event_t *static_evt; + void *tag; + void *data; +}; + + +extern ngx_module_t ngx_rtmp_relay_module; + + +ngx_int_t ngx_rtmp_relay_pull(ngx_rtmp_session_t *s, ngx_str_t *name, + ngx_rtmp_relay_target_t *target); +ngx_int_t ngx_rtmp_relay_push(ngx_rtmp_session_t *s, ngx_str_t *name, + ngx_rtmp_relay_target_t *target); + + +#endif /* _NGX_RTMP_RELAY_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_send.c b/debian/modules/nginx-rtmp/ngx_rtmp_send.c new file mode 100644 index 0000000..c65deec --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_send.c @@ -0,0 +1,635 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_amf.h" +#include "ngx_rtmp_streams.h" + + +#define NGX_RTMP_USER_START(s, tp) \ + ngx_rtmp_header_t __h; \ + ngx_chain_t *__l; \ + ngx_buf_t *__b; \ + ngx_rtmp_core_srv_conf_t *__cscf; \ + \ + __cscf = ngx_rtmp_get_module_srv_conf( \ + s, ngx_rtmp_core_module); \ + memset(&__h, 0, sizeof(__h)); \ + __h.type = tp; \ + __h.csid = 2; \ + __l = ngx_rtmp_alloc_shared_buf(__cscf); \ + if (__l == NULL) { \ + return NULL; \ + } \ + __b = __l->buf; + +#define NGX_RTMP_UCTL_START(s, type, utype) \ + NGX_RTMP_USER_START(s, type); \ + *(__b->last++) = (u_char)((utype) >> 8); \ + *(__b->last++) = (u_char)(utype); + +#define NGX_RTMP_USER_OUT1(v) \ + *(__b->last++) = ((u_char*)&v)[0]; + +#define NGX_RTMP_USER_OUT4(v) \ + *(__b->last++) = ((u_char*)&v)[3]; \ + *(__b->last++) = ((u_char*)&v)[2]; \ + *(__b->last++) = ((u_char*)&v)[1]; \ + *(__b->last++) = ((u_char*)&v)[0]; + +#define NGX_RTMP_USER_END(s) \ + ngx_rtmp_prepare_message(s, &__h, NULL, __l); \ + return __l; + + +static ngx_int_t +ngx_rtmp_send_shared_packet(ngx_rtmp_session_t *s, ngx_chain_t *cl) +{ + ngx_rtmp_core_srv_conf_t *cscf; + ngx_int_t rc; + + if (cl == NULL) { + return NGX_ERROR; + } + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + rc = ngx_rtmp_send_message(s, cl, 0); + + ngx_rtmp_free_shared_chain(cscf, cl); + + return rc; +} + + +/* Protocol control messages */ + +ngx_chain_t * +ngx_rtmp_create_chunk_size(ngx_rtmp_session_t *s, uint32_t chunk_size) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "chunk_size=%uD", chunk_size); + + { + NGX_RTMP_USER_START(s, NGX_RTMP_MSG_CHUNK_SIZE); + + NGX_RTMP_USER_OUT4(chunk_size); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_chunk_size(ngx_rtmp_session_t *s, uint32_t chunk_size) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_chunk_size(s, chunk_size)); +} + + +ngx_chain_t * +ngx_rtmp_create_abort(ngx_rtmp_session_t *s, uint32_t csid) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: abort csid=%uD", csid); + + { + NGX_RTMP_USER_START(s, NGX_RTMP_MSG_CHUNK_SIZE); + + NGX_RTMP_USER_OUT4(csid); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_abort(ngx_rtmp_session_t *s, uint32_t csid) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_abort(s, csid)); +} + + +ngx_chain_t * +ngx_rtmp_create_ack(ngx_rtmp_session_t *s, uint32_t seq) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: ack seq=%uD", seq); + + { + NGX_RTMP_USER_START(s, NGX_RTMP_MSG_ACK); + + NGX_RTMP_USER_OUT4(seq); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_ack(ngx_rtmp_session_t *s, uint32_t seq) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_ack(s, seq)); +} + + +ngx_chain_t * +ngx_rtmp_create_ack_size(ngx_rtmp_session_t *s, uint32_t ack_size) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: ack_size=%uD", ack_size); + + { + NGX_RTMP_USER_START(s, NGX_RTMP_MSG_ACK_SIZE); + + NGX_RTMP_USER_OUT4(ack_size); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_ack_size(ngx_rtmp_session_t *s, uint32_t ack_size) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_ack_size(s, ack_size)); +} + + +ngx_chain_t * +ngx_rtmp_create_bandwidth(ngx_rtmp_session_t *s, uint32_t ack_size, + uint8_t limit_type) +{ + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: bandwidth ack_size=%uD limit=%d", + ack_size, (int)limit_type); + + { + NGX_RTMP_USER_START(s, NGX_RTMP_MSG_BANDWIDTH); + + NGX_RTMP_USER_OUT4(ack_size); + NGX_RTMP_USER_OUT1(limit_type); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_bandwidth(ngx_rtmp_session_t *s, uint32_t ack_size, + uint8_t limit_type) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_bandwidth(s, ack_size, limit_type)); +} + + +/* User control messages */ + +ngx_chain_t * +ngx_rtmp_create_stream_begin(ngx_rtmp_session_t *s, uint32_t msid) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: stream_begin msid=%uD", msid); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_STREAM_BEGIN); + + NGX_RTMP_USER_OUT4(msid); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_stream_begin(ngx_rtmp_session_t *s, uint32_t msid) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_stream_begin(s, msid)); +} + + +ngx_chain_t * +ngx_rtmp_create_stream_eof(ngx_rtmp_session_t *s, uint32_t msid) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: stream_end msid=%uD", msid); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_STREAM_EOF); + + NGX_RTMP_USER_OUT4(msid); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_stream_eof(ngx_rtmp_session_t *s, uint32_t msid) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_stream_eof(s, msid)); +} + + +ngx_chain_t * +ngx_rtmp_create_stream_dry(ngx_rtmp_session_t *s, uint32_t msid) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: stream_dry msid=%uD", msid); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_STREAM_DRY); + + NGX_RTMP_USER_OUT4(msid); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_stream_dry(ngx_rtmp_session_t *s, uint32_t msid) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_stream_dry(s, msid)); +} + + +ngx_chain_t * +ngx_rtmp_create_set_buflen(ngx_rtmp_session_t *s, uint32_t msid, + uint32_t buflen_msec) +{ + ngx_log_debug2(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: set_buflen msid=%uD buflen=%uD", + msid, buflen_msec); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_SET_BUFLEN); + + NGX_RTMP_USER_OUT4(msid); + NGX_RTMP_USER_OUT4(buflen_msec); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_set_buflen(ngx_rtmp_session_t *s, uint32_t msid, + uint32_t buflen_msec) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_set_buflen(s, msid, buflen_msec)); +} + + +ngx_chain_t * +ngx_rtmp_create_recorded(ngx_rtmp_session_t *s, uint32_t msid) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: recorded msid=%uD", msid); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_RECORDED); + + NGX_RTMP_USER_OUT4(msid); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_recorded(ngx_rtmp_session_t *s, uint32_t msid) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_recorded(s, msid)); +} + + +ngx_chain_t * +ngx_rtmp_create_ping_request(ngx_rtmp_session_t *s, uint32_t timestamp) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: ping_request timestamp=%uD", timestamp); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_PING_REQUEST); + + NGX_RTMP_USER_OUT4(timestamp); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_ping_request(ngx_rtmp_session_t *s, uint32_t timestamp) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_ping_request(s, timestamp)); +} + + +ngx_chain_t * +ngx_rtmp_create_ping_response(ngx_rtmp_session_t *s, uint32_t timestamp) +{ + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: ping_response timestamp=%uD", timestamp); + + { + NGX_RTMP_UCTL_START(s, NGX_RTMP_MSG_USER, NGX_RTMP_USER_PING_RESPONSE); + + NGX_RTMP_USER_OUT4(timestamp); + + NGX_RTMP_USER_END(s); + } +} + + +ngx_int_t +ngx_rtmp_send_ping_response(ngx_rtmp_session_t *s, uint32_t timestamp) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_ping_response(s, timestamp)); +} + + +static ngx_chain_t * +ngx_rtmp_alloc_amf_buf(void *arg) +{ + return ngx_rtmp_alloc_shared_buf((ngx_rtmp_core_srv_conf_t *)arg); +} + + +/* AMF sender */ + +/* NOTE: this function does not free shared bufs on error */ +ngx_int_t +ngx_rtmp_append_amf(ngx_rtmp_session_t *s, + ngx_chain_t **first, ngx_chain_t **last, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + ngx_rtmp_amf_ctx_t act; + ngx_rtmp_core_srv_conf_t *cscf; + ngx_int_t rc; + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + memset(&act, 0, sizeof(act)); + act.arg = cscf; + act.alloc = ngx_rtmp_alloc_amf_buf; + act.log = s->connection->log; + + if (first) { + act.first = *first; + } + + if (last) { + act.link = *last; + } + + rc = ngx_rtmp_amf_write(&act, elts, nelts); + + if (first) { + *first = act.first; + } + + if (last) { + *last = act.link; + } + + return rc; +} + + +ngx_chain_t * +ngx_rtmp_create_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + ngx_chain_t *first; + ngx_int_t rc; + ngx_rtmp_core_srv_conf_t *cscf; + + ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: amf nelts=%ui", nelts); + + cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module); + + first = NULL; + + rc = ngx_rtmp_append_amf(s, &first, NULL, elts, nelts); + + if (rc != NGX_OK && first) { + ngx_rtmp_free_shared_chain(cscf, first); + first = NULL; + } + + if (first) { + ngx_rtmp_prepare_message(s, h, NULL, first); + } + + return first; +} + + +ngx_int_t +ngx_rtmp_send_amf(ngx_rtmp_session_t *s, ngx_rtmp_header_t *h, + ngx_rtmp_amf_elt_t *elts, size_t nelts) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_amf(s, h, elts, nelts)); +} + + +ngx_chain_t * +ngx_rtmp_create_status(ngx_rtmp_session_t *s, char *code, char* level, + char *desc) +{ + ngx_rtmp_header_t h; + static double trans; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("code"), + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("description"), + NULL, 0 }, + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onStatus", 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_null_string, + &trans, 0 }, + + { NGX_RTMP_AMF_NULL, + ngx_null_string, + NULL, 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, + sizeof(out_inf) }, + }; + + ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: status code='%s' level='%s' desc='%s'", + code, level, desc); + + out_inf[0].data = level; + out_inf[1].data = code; + out_inf[2].data = desc; + + memset(&h, 0, sizeof(h)); + + h.type = NGX_RTMP_MSG_AMF_CMD; + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + + return ngx_rtmp_create_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} + + +ngx_int_t +ngx_rtmp_send_status(ngx_rtmp_session_t *s, char *code, char* level, char *desc) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_status(s, code, level, desc)); +} + + +ngx_chain_t * +ngx_rtmp_create_play_status(ngx_rtmp_session_t *s, char *code, char* level, + ngx_uint_t duration, ngx_uint_t bytes) +{ + ngx_rtmp_header_t h; + static double dduration; + static double dbytes; + + static ngx_rtmp_amf_elt_t out_inf[] = { + + { NGX_RTMP_AMF_STRING, + ngx_string("code"), + NULL, 0 }, + + { NGX_RTMP_AMF_STRING, + ngx_string("level"), + NULL, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("duration"), + &dduration, 0 }, + + { NGX_RTMP_AMF_NUMBER, + ngx_string("bytes"), + &dbytes, 0 }, + }; + + static ngx_rtmp_amf_elt_t out_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "onPlayStatus", 0 }, + + { NGX_RTMP_AMF_OBJECT, + ngx_null_string, + out_inf, + sizeof(out_inf) }, + }; + + ngx_log_debug4(NGX_LOG_DEBUG_RTMP, s->connection->log, 0, + "create: play_status code='%s' level='%s' " + "duration=%ui bytes=%ui", + code, level, duration, bytes); + + out_inf[0].data = code; + out_inf[1].data = level; + + dduration = duration; + dbytes = bytes; + + memset(&h, 0, sizeof(h)); + + h.type = NGX_RTMP_MSG_AMF_META; + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + h.timestamp = duration; + + return ngx_rtmp_create_amf(s, &h, out_elts, + sizeof(out_elts) / sizeof(out_elts[0])); +} + + +ngx_int_t +ngx_rtmp_send_play_status(ngx_rtmp_session_t *s, char *code, char* level, + ngx_uint_t duration, ngx_uint_t bytes) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_play_status(s, code, level, duration, bytes)); +} + + +ngx_chain_t * +ngx_rtmp_create_sample_access(ngx_rtmp_session_t *s) +{ + ngx_rtmp_header_t h; + + static int access = 1; + + static ngx_rtmp_amf_elt_t access_elts[] = { + + { NGX_RTMP_AMF_STRING, + ngx_null_string, + "|RtmpSampleAccess", 0 }, + + { NGX_RTMP_AMF_BOOLEAN, + ngx_null_string, + &access, 0 }, + + { NGX_RTMP_AMF_BOOLEAN, + ngx_null_string, + &access, 0 }, + }; + + memset(&h, 0, sizeof(h)); + + h.type = NGX_RTMP_MSG_AMF_META; + h.csid = NGX_RTMP_CSID_AMF; + h.msid = NGX_RTMP_MSID; + + return ngx_rtmp_create_amf(s, &h, access_elts, + sizeof(access_elts) / sizeof(access_elts[0])); +} + + +ngx_int_t +ngx_rtmp_send_sample_access(ngx_rtmp_session_t *s) +{ + return ngx_rtmp_send_shared_packet(s, + ngx_rtmp_create_sample_access(s)); +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_shared.c b/debian/modules/nginx-rtmp/ngx_rtmp_shared.c new file mode 100644 index 0000000..6f6e4e8 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_shared.c @@ -0,0 +1,126 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include "ngx_rtmp.h" + + +ngx_chain_t * +ngx_rtmp_alloc_shared_buf(ngx_rtmp_core_srv_conf_t *cscf) +{ + u_char *p; + ngx_chain_t *out; + ngx_buf_t *b; + size_t size; + + if (cscf->free) { + out = cscf->free; + cscf->free = out->next; + + } else { + + size = cscf->chunk_size + NGX_RTMP_MAX_CHUNK_HEADER; + + p = ngx_pcalloc(cscf->pool, NGX_RTMP_REFCOUNT_BYTES + + sizeof(ngx_chain_t) + + sizeof(ngx_buf_t) + + size); + if (p == NULL) { + return NULL; + } + + p += NGX_RTMP_REFCOUNT_BYTES; + out = (ngx_chain_t *)p; + + p += sizeof(ngx_chain_t); + out->buf = (ngx_buf_t *)p; + + p += sizeof(ngx_buf_t); + out->buf->start = p; + out->buf->end = p + size; + } + + out->next = NULL; + b = out->buf; + b->pos = b->last = b->start + NGX_RTMP_MAX_CHUNK_HEADER; + b->memory = 1; + + /* buffer has refcount =1 when created! */ + ngx_rtmp_ref_set(out, 1); + + return out; +} + + +void +ngx_rtmp_free_shared_chain(ngx_rtmp_core_srv_conf_t *cscf, ngx_chain_t *in) +{ + ngx_chain_t *cl; + + if (ngx_rtmp_ref_put(in)) { + return; + } + + for (cl = in; ; cl = cl->next) { + if (cl->next == NULL) { + cl->next = cscf->free; + cscf->free = in; + return; + } + } +} + + +ngx_chain_t * +ngx_rtmp_append_shared_bufs(ngx_rtmp_core_srv_conf_t *cscf, + ngx_chain_t *head, ngx_chain_t *in) +{ + ngx_chain_t *l, **ll; + u_char *p; + size_t size; + + ll = &head; + p = in->buf->pos; + l = head; + + if (l) { + for(; l->next; l = l->next); + ll = &l->next; + } + + for ( ;; ) { + + if (l == NULL || l->buf->last == l->buf->end) { + l = ngx_rtmp_alloc_shared_buf(cscf); + if (l == NULL || l->buf == NULL) { + break; + } + + *ll = l; + ll = &l->next; + } + + while (l->buf->end - l->buf->last >= in->buf->last - p) { + l->buf->last = ngx_cpymem(l->buf->last, p, + in->buf->last - p); + in = in->next; + if (in == NULL) { + goto done; + } + p = in->buf->pos; + } + + size = l->buf->end - l->buf->last; + l->buf->last = ngx_cpymem(l->buf->last, p, size); + p += size; + } + +done: + *ll = NULL; + + return head; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c b/debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c new file mode 100644 index 0000000..326a811 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c @@ -0,0 +1,863 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#include +#include +#include +#include +#include "ngx_rtmp.h" +#include "ngx_rtmp_version.h" +#include "ngx_rtmp_live_module.h" +#include "ngx_rtmp_play_module.h" +#include "ngx_rtmp_codec_module.h" + + +static ngx_int_t ngx_rtmp_stat_init_process(ngx_cycle_t *cycle); +static char *ngx_rtmp_stat(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_rtmp_stat_postconfiguration(ngx_conf_t *cf); +static void * ngx_rtmp_stat_create_loc_conf(ngx_conf_t *cf); +static char * ngx_rtmp_stat_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static time_t start_time; + + +#define NGX_RTMP_STAT_ALL 0xff +#define NGX_RTMP_STAT_GLOBAL 0x01 +#define NGX_RTMP_STAT_LIVE 0x02 +#define NGX_RTMP_STAT_CLIENTS 0x04 +#define NGX_RTMP_STAT_PLAY 0x08 + +/* + * global: stat-{bufs-{total,free,used}, total bytes in/out, bw in/out} - cscf +*/ + + +typedef struct { + ngx_uint_t stat; + ngx_str_t stylesheet; +} ngx_rtmp_stat_loc_conf_t; + + +static ngx_conf_bitmask_t ngx_rtmp_stat_masks[] = { + { ngx_string("all"), NGX_RTMP_STAT_ALL }, + { ngx_string("global"), NGX_RTMP_STAT_GLOBAL }, + { ngx_string("live"), NGX_RTMP_STAT_LIVE }, + { ngx_string("clients"), NGX_RTMP_STAT_CLIENTS }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_rtmp_stat_commands[] = { + + { ngx_string("rtmp_stat"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_rtmp_stat, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_rtmp_stat_loc_conf_t, stat), + ngx_rtmp_stat_masks }, + + { ngx_string("rtmp_stat_stylesheet"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_rtmp_stat_loc_conf_t, stylesheet), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_rtmp_stat_module_ctx = { + NULL, /* preconfiguration */ + ngx_rtmp_stat_postconfiguration, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_rtmp_stat_create_loc_conf, /* create location configuration */ + ngx_rtmp_stat_merge_loc_conf, /* merge location configuration */ +}; + + +ngx_module_t ngx_rtmp_stat_module = { + NGX_MODULE_V1, + &ngx_rtmp_stat_module_ctx, /* module context */ + ngx_rtmp_stat_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_rtmp_stat_init_process, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +#define NGX_RTMP_STAT_BUFSIZE 256 + + +static ngx_int_t +ngx_rtmp_stat_init_process(ngx_cycle_t *cycle) +{ + /* + * HTTP process initializer is called + * after event module initializer + * so we can run posted events here + */ + + ngx_event_process_posted(cycle, &ngx_rtmp_init_queue); + + return NGX_OK; +} + + +/* ngx_escape_html does not escape characters out of ASCII range + * which are bad for xslt */ + +static void * +ngx_rtmp_stat_escape(ngx_http_request_t *r, void *data, size_t len) +{ + u_char *p, *np; + void *new_data; + size_t n; + + p = data; + + for (n = 0; n < len; ++n, ++p) { + if (*p < 0x20 || *p >= 0x7f) { + break; + } + } + + if (n == len) { + return data; + } + + new_data = ngx_palloc(r->pool, len); + if (new_data == NULL) { + return NULL; + } + + p = data; + np = new_data; + + for (n = 0; n < len; ++n, ++p, ++np) { + *np = (*p < 0x20 || *p >= 0x7f) ? (u_char) ' ' : *p; + } + + return new_data; +} + +#if (NGX_WIN32) +/* + * Fix broken MSVC memcpy optimization for 4-byte data + * when this function is inlined + */ +__declspec(noinline) +#endif + +static void +ngx_rtmp_stat_output(ngx_http_request_t *r, ngx_chain_t ***lll, + void *data, size_t len, ngx_uint_t escape) +{ + ngx_chain_t *cl; + ngx_buf_t *b; + size_t real_len; + + if (len == 0) { + return; + } + + if (escape) { + data = ngx_rtmp_stat_escape(r, data, len); + if (data == NULL) { + return; + } + } + + real_len = escape + ? len + ngx_escape_html(NULL, data, len) + : len; + + cl = **lll; + if (cl && cl->buf->last + real_len > cl->buf->end) { + *lll = &cl->next; + } + + if (**lll == NULL) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return; + } + b = ngx_create_temp_buf(r->pool, + ngx_max(NGX_RTMP_STAT_BUFSIZE, real_len)); + if (b == NULL || b->pos == NULL) { + return; + } + cl->next = NULL; + cl->buf = b; + **lll = cl; + } + + b = (**lll)->buf; + + if (escape) { + b->last = (u_char *)ngx_escape_html(b->last, data, len); + } else { + b->last = ngx_cpymem(b->last, data, len); + } +} + + +/* These shortcuts assume 2 variables exist in current context: + * ngx_http_request_t *r + * ngx_chain_t ***lll */ + +/* plain data */ +#define NGX_RTMP_STAT(data, len) ngx_rtmp_stat_output(r, lll, data, len, 0) + +/* escaped data */ +#define NGX_RTMP_STAT_E(data, len) ngx_rtmp_stat_output(r, lll, data, len, 1) + +/* literal */ +#define NGX_RTMP_STAT_L(s) NGX_RTMP_STAT((s), sizeof(s) - 1) + +/* ngx_str_t */ +#define NGX_RTMP_STAT_S(s) NGX_RTMP_STAT((s)->data, (s)->len) + +/* escaped ngx_str_t */ +#define NGX_RTMP_STAT_ES(s) NGX_RTMP_STAT_E((s)->data, (s)->len) + +/* C string */ +#define NGX_RTMP_STAT_CS(s) NGX_RTMP_STAT((s), ngx_strlen(s)) + +/* escaped C string */ +#define NGX_RTMP_STAT_ECS(s) NGX_RTMP_STAT_E((s), ngx_strlen(s)) + + +#define NGX_RTMP_STAT_BW 0x01 +#define NGX_RTMP_STAT_BYTES 0x02 +#define NGX_RTMP_STAT_BW_BYTES 0x03 + + +static void +ngx_rtmp_stat_bw(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_rtmp_bandwidth_t *bw, char *name, + ngx_uint_t flags) +{ + u_char buf[NGX_INT64_LEN + 9]; + + ngx_rtmp_update_bandwidth(bw, 0); + + if (flags & NGX_RTMP_STAT_BW) { + NGX_RTMP_STAT_L("%uLbandwidth * 8) + - buf); + NGX_RTMP_STAT_CS(name); + NGX_RTMP_STAT_L(">\r\n"); + } + + if (flags & NGX_RTMP_STAT_BYTES) { + NGX_RTMP_STAT_L("%uLbytes) + - buf); + NGX_RTMP_STAT_CS(name); + NGX_RTMP_STAT_L(">\r\n"); + } +} + + +#ifdef NGX_RTMP_POOL_DEBUG +static void +ngx_rtmp_stat_get_pool_size(ngx_pool_t *pool, ngx_uint_t *nlarge, + ngx_uint_t *size) +{ + ngx_pool_large_t *l; + ngx_pool_t *p, *n; + + *nlarge = 0; + for (l = pool->large; l; l = l->next) { + ++*nlarge; + } + + *size = 0; + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { + *size += (p->d.last - (u_char *)p); + if (n == NULL) { + break; + } + } +} + + +static void +ngx_rtmp_stat_dump_pool(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_pool_t *pool) +{ + ngx_uint_t nlarge, size; + u_char buf[NGX_INT_T_LEN]; + + size = 0; + nlarge = 0; + ngx_rtmp_stat_get_pool_size(pool, &nlarge, &size); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", nlarge) - buf); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", size) - buf); + NGX_RTMP_STAT_L("\r\n"); +} +#endif + + + +static void +ngx_rtmp_stat_client(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_rtmp_session_t *s) +{ + u_char buf[NGX_INT_T_LEN]; + +#ifdef NGX_RTMP_POOL_DEBUG + ngx_rtmp_stat_dump_pool(r, lll, s->connection->pool); +#endif + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), "%ui", + (ngx_uint_t) s->connection->number) - buf); + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L("
"); + NGX_RTMP_STAT_ES(&s->connection->addr_text); + NGX_RTMP_STAT_L("
"); + + NGX_RTMP_STAT_L(""); + + if (s->flashver.len) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&s->flashver); + NGX_RTMP_STAT_L(""); + } + + if (s->page_url.len) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&s->page_url); + NGX_RTMP_STAT_L(""); + } + + if (s->swf_url.len) { + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&s->swf_url); + NGX_RTMP_STAT_L(""); + } +} + + +static char * +ngx_rtmp_stat_get_aac_profile(ngx_uint_t p, ngx_uint_t sbr, ngx_uint_t ps) { + switch (p) { + case 1: + return "Main"; + case 2: + if (ps) { + return "HEv2"; + } + if (sbr) { + return "HE"; + } + return "LC"; + case 3: + return "SSR"; + case 4: + return "LTP"; + case 5: + return "SBR"; + default: + return ""; + } +} + + +static char * +ngx_rtmp_stat_get_avc_profile(ngx_uint_t p) { + switch (p) { + case 66: + return "Baseline"; + case 77: + return "Main"; + case 100: + return "High"; + default: + return ""; + } +} + + +static void +ngx_rtmp_stat_live(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_rtmp_live_app_conf_t *lacf) +{ + ngx_rtmp_live_stream_t *stream; + ngx_rtmp_codec_ctx_t *codec; + ngx_rtmp_live_ctx_t *ctx; + ngx_rtmp_session_t *s; + ngx_int_t n; + ngx_uint_t nclients, total_nclients; + u_char buf[NGX_INT_T_LEN]; + u_char bbuf[NGX_INT32_LEN]; + ngx_rtmp_stat_loc_conf_t *slcf; + u_char *cname; + + if (!lacf->live) { + return; + } + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + + NGX_RTMP_STAT_L("\r\n"); + + total_nclients = 0; + for (n = 0; n < lacf->nbuckets; ++n) { + for (stream = lacf->streams[n]; stream; stream = stream->next) { + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ECS(stream->name); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + + ngx_rtmp_stat_bw(r, lll, &stream->bw_in, "in", + NGX_RTMP_STAT_BW_BYTES); + ngx_rtmp_stat_bw(r, lll, &stream->bw_out, "out", + NGX_RTMP_STAT_BW_BYTES); + ngx_rtmp_stat_bw(r, lll, &stream->bw_in_audio, "audio", + NGX_RTMP_STAT_BW); + ngx_rtmp_stat_bw(r, lll, &stream->bw_in_video, "video", + NGX_RTMP_STAT_BW); + + nclients = 0; + codec = NULL; + for (ctx = stream->ctx; ctx; ctx = ctx->next, ++nclients) { + s = ctx->session; + if (slcf->stat & NGX_RTMP_STAT_CLIENTS) { + NGX_RTMP_STAT_L(""); + + ngx_rtmp_stat_client(r, lll, s); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", ctx->ndropped) - buf); + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L(""); + if (!lacf->interleave) { + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", ctx->cs[1].timestamp - + ctx->cs[0].timestamp) - bbuf); + } + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", s->current_time) - bbuf); + NGX_RTMP_STAT_L(""); + + if (ctx->publishing) { + NGX_RTMP_STAT_L(""); + } + + if (ctx->active) { + NGX_RTMP_STAT_L(""); + } + + NGX_RTMP_STAT_L("\r\n"); + } + if (ctx->publishing) { + codec = ngx_rtmp_get_module_ctx(s, ngx_rtmp_codec_module); + } + } + total_nclients += nclients; + + if (codec) { + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L("\r\n"); + } + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + + if (stream->publishing) { + NGX_RTMP_STAT_L("\r\n"); + } + + if (stream->active) { + NGX_RTMP_STAT_L("\r\n"); + } + + NGX_RTMP_STAT_L("\r\n"); + } + } + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", total_nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L("\r\n"); +} + + +static void +ngx_rtmp_stat_play(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_rtmp_play_app_conf_t *pacf) +{ + ngx_rtmp_play_ctx_t *ctx, *sctx; + ngx_rtmp_session_t *s; + ngx_uint_t n, nclients, total_nclients; + u_char buf[NGX_INT_T_LEN]; + u_char bbuf[NGX_INT32_LEN]; + ngx_rtmp_stat_loc_conf_t *slcf; + + if (pacf->entries.nelts == 0) { + return; + } + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + + NGX_RTMP_STAT_L("\r\n"); + + total_nclients = 0; + for (n = 0; n < pacf->nbuckets; ++n) { + for (ctx = pacf->ctx[n]; ctx; ) { + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ECS(ctx->name); + NGX_RTMP_STAT_L("\r\n"); + + nclients = 0; + sctx = ctx; + for (; ctx; ctx = ctx->next) { + if (ngx_strcmp(ctx->name, sctx->name)) { + break; + } + + nclients++; + + s = ctx->session; + if (slcf->stat & NGX_RTMP_STAT_CLIENTS) { + NGX_RTMP_STAT_L(""); + + ngx_rtmp_stat_client(r, lll, s); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(bbuf, ngx_snprintf(bbuf, sizeof(bbuf), + "%D", s->current_time) - bbuf); + NGX_RTMP_STAT_L(""); + + NGX_RTMP_STAT_L("\r\n"); + } + } + total_nclients += nclients; + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L("\r\n"); + } + } + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(buf, ngx_snprintf(buf, sizeof(buf), + "%ui", total_nclients) - buf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L("\r\n"); +} + + +static void +ngx_rtmp_stat_application(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_rtmp_core_app_conf_t *cacf) +{ + ngx_rtmp_stat_loc_conf_t *slcf; + + NGX_RTMP_STAT_L("\r\n"); + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT_ES(&cacf->name); + NGX_RTMP_STAT_L("\r\n"); + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + + if (slcf->stat & NGX_RTMP_STAT_LIVE) { + ngx_rtmp_stat_live(r, lll, + cacf->app_conf[ngx_rtmp_live_module.ctx_index]); + } + + if (slcf->stat & NGX_RTMP_STAT_PLAY) { + ngx_rtmp_stat_play(r, lll, + cacf->app_conf[ngx_rtmp_play_module.ctx_index]); + } + + NGX_RTMP_STAT_L("\r\n"); +} + + +static void +ngx_rtmp_stat_server(ngx_http_request_t *r, ngx_chain_t ***lll, + ngx_rtmp_core_srv_conf_t *cscf) +{ + ngx_rtmp_core_app_conf_t **cacf; + size_t n; + + NGX_RTMP_STAT_L("\r\n"); + +#ifdef NGX_RTMP_POOL_DEBUG + ngx_rtmp_stat_dump_pool(r, lll, cscf->pool); +#endif + + cacf = cscf->applications.elts; + for (n = 0; n < cscf->applications.nelts; ++n, ++cacf) { + ngx_rtmp_stat_application(r, lll, *cacf); + } + + NGX_RTMP_STAT_L("\r\n"); +} + + +static ngx_int_t +ngx_rtmp_stat_handler(ngx_http_request_t *r) +{ + ngx_rtmp_stat_loc_conf_t *slcf; + ngx_rtmp_core_main_conf_t *cmcf; + ngx_rtmp_core_srv_conf_t **cscf; + ngx_chain_t *cl, *l, **ll, ***lll; + size_t n; + off_t len; + static u_char tbuf[NGX_TIME_T_LEN]; + static u_char nbuf[NGX_INT_T_LEN]; + + slcf = ngx_http_get_module_loc_conf(r, ngx_rtmp_stat_module); + if (slcf->stat == 0) { + return NGX_DECLINED; + } + + cmcf = ngx_rtmp_core_main_conf; + if (cmcf == NULL) { + goto error; + } + + cl = NULL; + ll = &cl; + lll = ≪ + + NGX_RTMP_STAT_L("\r\n"); + if (slcf->stylesheet.len) { + NGX_RTMP_STAT_L("stylesheet); + NGX_RTMP_STAT_L("\" ?>\r\n"); + } + + NGX_RTMP_STAT_L("\r\n"); + +#ifdef NGINX_VERSION + NGX_RTMP_STAT_L("" NGINX_VERSION "\r\n"); +#endif + +#ifdef NGINX_RTMP_VERSION + NGX_RTMP_STAT_L("" NGINX_RTMP_VERSION "\r\n"); +#endif + +#ifdef NGX_COMPILER + NGX_RTMP_STAT_L("" NGX_COMPILER "\r\n"); +#endif + NGX_RTMP_STAT_L("" __DATE__ " " __TIME__ "\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), + "%ui", (ngx_uint_t) ngx_getpid()) - nbuf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(tbuf, ngx_snprintf(tbuf, sizeof(tbuf), + "%T", ngx_cached_time->sec - start_time) - tbuf); + NGX_RTMP_STAT_L("\r\n"); + + NGX_RTMP_STAT_L(""); + NGX_RTMP_STAT(nbuf, ngx_snprintf(nbuf, sizeof(nbuf), + "%ui", ngx_rtmp_naccepted) - nbuf); + NGX_RTMP_STAT_L("\r\n"); + + ngx_rtmp_stat_bw(r, lll, &ngx_rtmp_bw_in, "in", NGX_RTMP_STAT_BW_BYTES); + ngx_rtmp_stat_bw(r, lll, &ngx_rtmp_bw_out, "out", NGX_RTMP_STAT_BW_BYTES); + + cscf = cmcf->servers.elts; + for (n = 0; n < cmcf->servers.nelts; ++n, ++cscf) { + ngx_rtmp_stat_server(r, lll, *cscf); + } + + NGX_RTMP_STAT_L("\r\n"); + + len = 0; + for (l = cl; l; l = l->next) { + len += (l->buf->last - l->buf->pos); + } + ngx_str_set(&r->headers_out.content_type, "text/xml"); + r->headers_out.content_length_n = len; + r->headers_out.status = NGX_HTTP_OK; + ngx_http_send_header(r); + (*ll)->buf->last_buf = 1; + return ngx_http_output_filter(r, cl); + +error: + r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR; + r->headers_out.content_length_n = 0; + return ngx_http_send_header(r); +} + + +static void * +ngx_rtmp_stat_create_loc_conf(ngx_conf_t *cf) +{ + ngx_rtmp_stat_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_rtmp_stat_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->stat = 0; + + return conf; +} + + +static char * +ngx_rtmp_stat_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_rtmp_stat_loc_conf_t *prev = parent; + ngx_rtmp_stat_loc_conf_t *conf = child; + + ngx_conf_merge_bitmask_value(conf->stat, prev->stat, 0); + ngx_conf_merge_str_value(conf->stylesheet, prev->stylesheet, ""); + + return NGX_CONF_OK; +} + + +static char * +ngx_rtmp_stat(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_rtmp_stat_handler; + + return ngx_conf_set_bitmask_slot(cf, cmd, conf); +} + + +static ngx_int_t +ngx_rtmp_stat_postconfiguration(ngx_conf_t *cf) +{ + start_time = ngx_cached_time->sec; + + return NGX_OK; +} diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_streams.h b/debian/modules/nginx-rtmp/ngx_rtmp_streams.h new file mode 100644 index 0000000..d957b8e --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_streams.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_STREAMS_H_INCLUDED_ +#define _NGX_RTMP_STREAMS_H_INCLUDED_ + + +#define NGX_RTMP_MSID 1 + +#define NGX_RTMP_CSID_AMF_INI 3 +#define NGX_RTMP_CSID_AMF 5 +#define NGX_RTMP_CSID_AUDIO 6 +#define NGX_RTMP_CSID_VIDEO 7 + + +#endif /* _NGX_RTMP_STREAMS_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_version.h b/debian/modules/nginx-rtmp/ngx_rtmp_version.h new file mode 100644 index 0000000..1bdce49 --- /dev/null +++ b/debian/modules/nginx-rtmp/ngx_rtmp_version.h @@ -0,0 +1,15 @@ + +/* + * Copyright (C) Roman Arutyunyan + */ + + +#ifndef _NGX_RTMP_VERSION_H_INCLUDED_ +#define _NGX_RTMP_VERSION_H_INCLUDED_ + + +#define nginx_rtmp_version 1001004 +#define NGINX_RTMP_VERSION "1.1.4" + + +#endif /* _NGX_RTMP_VERSION_H_INCLUDED_ */ diff --git a/debian/modules/nginx-rtmp/stat.xsl b/debian/modules/nginx-rtmp/stat.xsl new file mode 100644 index 0000000..355453b --- /dev/null +++ b/debian/modules/nginx-rtmp/stat.xsl @@ -0,0 +1,355 @@ + + + + + + + + + + + + + RTMP statistics + + + +
+ Generated by + nginx-rtmp-module , + nginx , + pid , + built   + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RTMP#clientsVideoAudioIn bytesOut bytesIn bits/sOut bits/sStateTime
Accepted: codecbits/ssizefpscodecbits/sfreqchan + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + live streams + + + + + + + + + + + + vod streams + + + + + + + + + + + + + #cccccc + #dddddd + + + + + + var d=document.getElementById('-'); + d.style.display=d.style.display=='none'?'':'none'; + return false + + + + [EMPTY] + + + + + +    + + + + + + + + + + + + + + + +   + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + +
IdStateAddressFlash versionPage URLSWF URLDroppedTimestampA-VTime
+ + +
+ + + + + + + + + + + d + + + + h + + + + m + + + s + + + + + + + + + + + + + T + + + G + + + M + + K + + + + b + B + + /s + + + + + + active + idle + + + + + + + publishing + playing + + + + + + + + + #cccccc + #eeeeee + + + + + + + + http://apps.db.ripe.net/search/query.html?searchtext= + + whois + + + + + + + + + + + + + + + + + + + + + + + + + + publishing + + + + active + + + + x + + +
diff --git a/debian/rules b/debian/rules index 9ca4443..3951529 100755 --- a/debian/rules +++ b/debian/rules @@ -24,6 +24,7 @@ DYN_MODS := \ http-xslt-filter \ mail \ nchan \ + rtmp \ stream MODULESDIR = $(CURDIR)/debian/modules @@ -131,6 +132,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ --add-dynamic-module=$(MODULESDIR)/nchan \ --add-dynamic-module=$(MODULESDIR)/nginx-lua \ + --add-dynamic-module=$(MODULESDIR)/nginx-rtmp \ --add-dynamic-module=$(MODULESDIR)/nginx-upload-progress \ --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module diff --git a/debian/tests/control b/debian/tests/control index 03cd901..d276e4f 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -34,6 +34,7 @@ Depends: nginx-full, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-nchan, + libnginx-mod-rtmp, libnginx-mod-stream Tests: light-module-deps @@ -56,6 +57,7 @@ Depends: nginx-light, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-nchan, + libnginx-mod-rtmp, libnginx-mod-stream Tests: extras-module-deps @@ -78,4 +80,5 @@ Depends: nginx-extras, libnginx-mod-http-xslt-filter, libnginx-mod-mail, libnginx-mod-nchan, + libnginx-mod-rtmp, libnginx-mod-stream From d546f527ee6fb613a571829ee50816462ceefaa6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 30 Jun 2017 22:02:19 +0300 Subject: [PATCH 011/414] Fix nginx-cache-purge segfaults The module copies verbatim the ngx_http_proxy_loc_conf_t struct, but the `method` member has changed since Nginx 1.11.6. Closes: #866750 --- debian/modules/README.Modules-versions | 1 + .../nginx-cache-purge/segfault-1.11.6.patch | 25 +++++++++++++++++++ .../modules/patches/nginx-cache-purge/series | 1 + 3 files changed, 27 insertions(+) create mode 100644 debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 8ed4610..c336064 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -47,6 +47,7 @@ README for Modules versions Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ Version: 2.3 Patch: dynamic-module.patch + Patch: segfault-1.11.6.patch nginx-dav-ext-module Homepage: https://github.com/arut/nginx-dav-ext-module diff --git a/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch b/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch new file mode 100644 index 0000000..11972c8 --- /dev/null +++ b/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch @@ -0,0 +1,25 @@ +From: Pawel Sulowicz +Date: Thu, 2 Feb 2017 09:39:37 +0100 +Subject: [PATCH] Fix compatibility with nginx-1.11.6+ +Origin: other, https://github.com/FRiCKLE/ngx_cache_purge/pull/51 + +--- + ngx_cache_purge_module.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/ngx_cache_purge_module.c b/ngx_cache_purge_module.c +index 62d3818..fd1ebde 100644 +--- a/ngx_cache_purge_module.c ++++ b/ngx_cache_purge_module.c +@@ -492,7 +492,11 @@ typedef struct { + 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; + diff --git a/debian/modules/patches/nginx-cache-purge/series b/debian/modules/patches/nginx-cache-purge/series index f9b9360..2876b35 100644 --- a/debian/modules/patches/nginx-cache-purge/series +++ b/debian/modules/patches/nginx-cache-purge/series @@ -1 +1,2 @@ dynamic-module.patch +segfault-1.11.6.patch From f4979c7c960b73049282ed87a07a7b7d7f72f91a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 3 Jul 2017 14:15:40 +0300 Subject: [PATCH 012/414] Switch the copyright-format URL to https Complements the debian-policy bump to 4.0.0 (22fe275) Gbp-Dch: Ignore --- debian/copyright | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/copyright b/debian/copyright index 78ea210..3d1b4c5 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: nginx Source: http://nginx.org/en/download.html From 5ccd94c7e9f19d6815e2b27e1325b8c3a8e626fc Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 3 Jul 2017 13:45:10 +0300 Subject: [PATCH 013/414] Release 1.13.2-1 --- debian/changelog | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/debian/changelog b/debian/changelog index fac5d1c..0b7711b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,22 @@ +nginx (1.13.2-1) unstable; urgency=medium + + [ Christos Trochalakis ] + * New upstream version 1.13.2. + * Fix nginx-cache-purge segfaults (Closes: #866750) + * Merge ca translations. + Thanks to Alytidae (Closes: #865996) + * Merge es translations. + Thanks to Jonathan Bustillos (Closes: #855610) + * Merge pt translations. + Thanks to Rui Branco (Closes: #858741) + * Bump Standards to 4.0.0. + - Switch the copyright-format URL to https. + + [ Nicolas Dandrimont ] + * Introduce libnginx-mod-rtmp (Closes: #843777) + + -- Christos Trochalakis Mon, 03 Jul 2017 13:44:59 +0300 + nginx (1.13.1-2) unstable; urgency=medium * Upload to unstable. From ab3dccab6aae29fd6a91d77aa8fc554c34e07a8c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 7 Jul 2017 13:01:25 +0300 Subject: [PATCH 014/414] Drop gzip_disable "msie6" directive. IE6 is really deprecated nowdays. Also, this only affected earlier IE6 versions that was later patched to fix this issue. Closes: #867024 --- debian/conf/nginx.conf | 1 - debian/help/examples/http | 1 - 2 files changed, 2 deletions(-) diff --git a/debian/conf/nginx.conf b/debian/conf/nginx.conf index 6e57ea9..132f680 100644 --- a/debian/conf/nginx.conf +++ b/debian/conf/nginx.conf @@ -46,7 +46,6 @@ http { ## gzip on; - gzip_disable "msie6"; # gzip_vary on; # gzip_proxied any; diff --git a/debian/help/examples/http b/debian/help/examples/http index 89b2dde..bac9f90 100644 --- a/debian/help/examples/http +++ b/debian/help/examples/http @@ -38,7 +38,6 @@ http { ## gzip on; - gzip_disable "msie6"; # gzip_vary on; # gzip_proxied any; From 3d12f812d7285ac862794e62e92098c166b741e2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 12 Jul 2017 08:12:27 +0300 Subject: [PATCH 015/414] New upstream version 1.13.3 --- CHANGES | 7 + CHANGES.ru | 8 + src/core/nginx.h | 4 +- src/core/ngx_resolver.c | 123 ++++++------- src/core/ngx_resolver.h | 1 + src/core/ngx_slab.c | 37 ++-- src/http/modules/ngx_http_proxy_module.c | 165 +++++++----------- .../modules/ngx_http_range_filter_module.c | 6 +- src/http/ngx_http_variables.c | 16 +- 9 files changed, 164 insertions(+), 203 deletions(-) diff --git a/CHANGES b/CHANGES index e7126ff..30b01ef 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,11 @@ +Changes with nginx 1.13.3 11 Jul 2017 + + *) Security: a specially crafted request might result in an integer + overflow and incorrect processing of ranges in the range filter, + potentially resulting in sensitive information leak (CVE-2017-7529). + + Changes with nginx 1.13.2 27 Jun 2017 *) Change: nginx now returns 200 instead of 416 when a range starting diff --git a/CHANGES.ru b/CHANGES.ru index 69e2be1..dab50c9 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,12 @@ +Изменения в nginx 1.13.3 11.07.2017 + + *) Безопасность: специально созданный запрос мог вызвать целочисленное + переполнение в range-фильтре и последующую некорректную обработку + запрошенных диапазонов, что потенциально могло привести к утечке + конфиденциальной информации (CVE-2017-7529). + + Изменения в nginx 1.13.2 27.06.2017 *) Изменение: теперь при запросе диапазона, начинающегося с 0, из diff --git a/src/core/nginx.h b/src/core/nginx.h index 37e257f..1f3a369 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013002 -#define NGINX_VERSION "1.13.2" +#define nginx_version 1013003 +#define NGINX_VERSION "1.13.3" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 91f8a5e..cd55520 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -105,6 +105,8 @@ static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, u_char *last); +static ngx_int_t ngx_resolver_set_timeout(ngx_resolver_t *r, + ngx_resolver_ctx_t *ctx); static void ngx_resolver_timeout_handler(ngx_event_t *ev); static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn); static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size); @@ -189,6 +191,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; + r->event->cancelable = 1; r->ident = -1; r->resend_timeout = 5; @@ -728,19 +731,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, } if (rn->waiting) { - - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + return NGX_ERROR; } last->next = rn->waiting; @@ -864,18 +856,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, goto failed; } - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + goto failed; } if (ngx_resolver_resend_empty(r)) { @@ -1007,19 +989,8 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) } if (rn->waiting) { - - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + return NGX_ERROR; } ctx->next = rn->waiting; @@ -1089,18 +1060,8 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) goto failed; } - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + goto failed; } if (ngx_resolver_resend_empty(r)) { @@ -3034,25 +2995,15 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t)); if (addrs == NULL) { - ngx_resolve_name_done(cctx); - - ctx->state = NGX_ERROR; - ctx->valid = ngx_time() + (r->valid ? r->valid : 10); - - ctx->handler(ctx); - return; + srv->state = NGX_ERROR; + goto done; } sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t)); if (sockaddr == NULL) { ngx_resolver_free(r, addrs); - ngx_resolve_name_done(cctx); - - ctx->state = NGX_ERROR; - ctx->valid = ngx_time() + (r->valid ? r->valid : 10); - - ctx->handler(ctx); - return; + srv->state = NGX_ERROR; + goto done; } for (i = 0; i < cctx->naddrs; i++) { @@ -3069,6 +3020,8 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) srv->naddrs = cctx->naddrs; } +done: + ngx_resolve_name_done(cctx); if (ctx->count == 0) { @@ -4041,6 +3994,30 @@ done: } +static ngx_int_t +ngx_resolver_set_timeout(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +{ + if (ctx->event || ctx->timeout == 0) { + return NGX_OK; + } + + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->event->cancelable = ctx->cancelable; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + + return NGX_OK; +} + + static void ngx_resolver_timeout_handler(ngx_event_t *ev) { @@ -4254,10 +4231,21 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_resolver_addr_t *addrs; ngx_resolver_srv_name_t *srvs; + srvs = ctx->srvs; + nsrvs = ctx->nsrvs; + naddrs = 0; - for (i = 0; i < ctx->nsrvs; i++) { - naddrs += ctx->srvs[i].naddrs; + for (i = 0; i < nsrvs; i++) { + if (srvs[i].state == NGX_ERROR) { + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + naddrs += srvs[i].naddrs; } if (naddrs == 0) { @@ -4277,9 +4265,6 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) return; } - srvs = ctx->srvs; - nsrvs = ctx->nsrvs; - i = 0; n = 0; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index 6f099b7..0bd3921 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -220,6 +220,7 @@ struct ngx_resolver_ctx_s { unsigned quick:1; unsigned async:1; + unsigned cancelable:1; ngx_uint_t recursion; ngx_event_t *event; }; diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 1d4ce2b..9e7796d 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -181,8 +181,8 @@ void * ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) { size_t s; - uintptr_t p, n, m, mask, *bitmap; - ngx_uint_t i, slot, shift, map; + uintptr_t p, m, mask, *bitmap; + ngx_uint_t i, n, slot, shift, map; ngx_slab_page_t *page, *prev, *slots; if (size > ngx_slab_max_size) { @@ -226,7 +226,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page); - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); for (n = 0; n < map; n++) { @@ -239,7 +239,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) bitmap[n] |= m; - i = (n * sizeof(uintptr_t) * 8 + i) << shift; + i = (n * 8 * sizeof(uintptr_t) + i) << shift; p = (uintptr_t) bitmap + i; @@ -339,11 +339,17 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) } /* "n" elements for bitmap, plus one requested */ - bitmap[0] = ((uintptr_t) 2 << n) - 1; - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + for (i = 0; i < (n + 1) / (8 * sizeof(uintptr_t)); i++) { + bitmap[i] = NGX_SLAB_BUSY; + } - for (i = 1; i < map; i++) { + m = ((uintptr_t) 1 << ((n + 1) % (8 * sizeof(uintptr_t)))) - 1; + bitmap[i] = m; + + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); + + for (i = i + 1; i < map; i++) { bitmap[i] = 0; } @@ -369,7 +375,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slots[slot].next = page; - pool->stats[slot].total += sizeof(uintptr_t) * 8; + pool->stats[slot].total += 8 * sizeof(uintptr_t); p = ngx_slab_page_addr(pool, page); @@ -480,8 +486,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) } n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; - m = (uintptr_t) 1 << (n % (sizeof(uintptr_t) * 8)); - n /= sizeof(uintptr_t) * 8; + m = (uintptr_t) 1 << (n % (8 * sizeof(uintptr_t))); + n /= 8 * sizeof(uintptr_t); bitmap = (uintptr_t *) ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1)); @@ -506,13 +512,16 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) n = 1; } - if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) { + i = n / (8 * sizeof(uintptr_t)); + m = ((uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)))) - 1; + + if (bitmap[i] & ~m) { goto done; } - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); - for (i = 1; i < map; i++) { + for (i = i + 1; i < map; i++) { if (bitmap[i]) { goto done; } @@ -558,7 +567,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) ngx_slab_free_pages(pool, page, 1); - pool->stats[slot].total -= sizeof(uintptr_t) * 8; + pool->stats[slot].total -= 8 * sizeof(uintptr_t); goto done; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 839d479..61bf55c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1143,7 +1143,8 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r) { - size_t len, uri_len, loc_len, body_len; + size_t len, uri_len, loc_len, body_len, + key_len, val_len; uintptr_t escape; ngx_buf_t *b; ngx_str_t method; @@ -1258,11 +1259,20 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) le.flushed = 1; while (*(uintptr_t *) le.ip) { - while (*(uintptr_t *) le.ip) { + + lcode = *(ngx_http_script_len_code_pt *) le.ip; + key_len = lcode(&le); + + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; - len += lcode(&le); } le.ip += sizeof(uintptr_t); + + if (val_len == 0) { + continue; + } + + len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1; } @@ -1362,30 +1372,41 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) le.ip = headers->lengths->elts; while (*(uintptr_t *) le.ip) { - lcode = *(ngx_http_script_len_code_pt *) le.ip; - /* skip the header line name length */ + lcode = *(ngx_http_script_len_code_pt *) le.ip; (void) lcode(&le); - if (*(ngx_http_script_len_code_pt *) le.ip) { + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + } + le.ip += sizeof(uintptr_t); - for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { - lcode = *(ngx_http_script_len_code_pt *) le.ip; + if (val_len == 0) { + e.skip = 1; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); } + e.ip += sizeof(uintptr_t); - e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0; - - } else { e.skip = 0; + + continue; } - le.ip += sizeof(uintptr_t); + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + + *e.pos++ = ':'; *e.pos++ = ' '; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); + + *e.pos++ = CR; *e.pos++ = LF; } b->last = e.pos; @@ -3498,108 +3519,40 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, continue; } - if (ngx_http_script_variables_count(&src[i].value) == 0) { - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } + copy = ngx_array_push_n(headers->lengths, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_ERROR; + } - copy->code = (ngx_http_script_code_pt) - ngx_http_script_copy_len_code; - copy->len = src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1; + copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; + copy->len = src[i].key.len; + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); - size = (sizeof(ngx_http_script_copy_code_t) - + src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1 - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); + copy = ngx_array_push_n(headers->values, size); + if (copy == NULL) { + return NGX_ERROR; + } - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len; - copy->code = ngx_http_script_copy_code; - copy->len = src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1; + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memcpy(p, src[i].key.data, src[i].key.len); - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - p = ngx_cpymem(p, src[i].key.data, src[i].key.len); - *p++ = ':'; *p++ = ' '; - p = ngx_cpymem(p, src[i].value.data, src[i].value.len); - *p++ = CR; *p = LF; + sc.cf = cf; + sc.source = &src[i].value; + sc.flushes = &headers->flushes; + sc.lengths = &headers->lengths; + sc.values = &headers->values; - } else { - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = (ngx_http_script_code_pt) - ngx_http_script_copy_len_code; - copy->len = src[i].key.len + sizeof(": ") - 1; - - - size = (sizeof(ngx_http_script_copy_code_t) - + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = ngx_http_script_copy_code; - copy->len = src[i].key.len + sizeof(": ") - 1; - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - p = ngx_cpymem(p, src[i].key.data, src[i].key.len); - *p++ = ':'; *p = ' '; - - - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &src[i].value; - sc.flushes = &headers->flushes; - sc.lengths = &headers->lengths; - sc.values = &headers->values; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_ERROR; - } - - - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = (ngx_http_script_code_pt) - ngx_http_script_copy_len_code; - copy->len = sizeof(CRLF) - 1; - - - size = (sizeof(ngx_http_script_copy_code_t) - + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = ngx_http_script_copy_code; - copy->len = sizeof(CRLF) - 1; - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - *p++ = CR; *p = LF; + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; } code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 7ad9db9..292a2b8 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -355,7 +355,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, } if (suffix) { - start = content_length - end; + start = (end < content_length) ? content_length - end : 0; end = content_length - 1; } @@ -377,6 +377,10 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, range->start = start; range->end = end; + if (size > NGX_MAX_OFF_T_VALUE - (end - start)) { + return NGX_HTTP_RANGE_NOT_SATISFIABLE; + } + size += end - start; if (ranges-- == 0) { diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index cfb538a..fbc9ffa 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -1463,17 +1463,15 @@ static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - if (r->args.len == 0) { - v->len = 0; - v->data = NULL; + *v = ngx_http_variable_null_value; return NGX_OK; } v->len = 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; v->data = (u_char *) "?"; return NGX_OK; @@ -1990,11 +1988,7 @@ ngx_http_variable_request_completion(ngx_http_request_t *r, return NGX_OK; } - v->len = 0; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = (u_char *) ""; + *v = ngx_http_variable_null_value; return NGX_OK; } From 95f7f656da1f216cba0e292813cf0889dff2dd04 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 12 Jul 2017 11:20:46 +0300 Subject: [PATCH 016/414] Release 1.13.3-1 --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 0b7711b..7d350cf 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +nginx (1.13.3-1) unstable; urgency=high + + * New upstream version 1.13.3. + Fixes CVE-2017-7529 (Closes: #868109) + * Drop gzip_disable "msie6" directive. (Closes: #867024) + + -- Christos Trochalakis Wed, 12 Jul 2017 11:20:27 +0300 + nginx (1.13.2-1) unstable; urgency=medium [ Christos Trochalakis ] From ec292afcb9b056d4434dd393c41b52d00fccceca Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 9 Aug 2017 09:05:28 +0300 Subject: [PATCH 017/414] New upstream version 1.13.4 --- CHANGES | 20 + CHANGES.ru | 20 + auto/lib/conf | 2 +- auto/modules | 22 + auto/options | 3 + src/core/nginx.c | 6 + src/core/nginx.h | 4 +- src/core/ngx_connection.c | 4 +- src/core/ngx_parse_time.c | 16 +- src/core/ngx_slab.c | 23 +- src/core/ngx_slab.h | 1 + src/core/ngx_string.c | 8 +- src/event/ngx_event_openssl.c | 2 +- src/event/ngx_event_openssl_stapling.c | 2 +- .../modules/ngx_http_addition_filter_module.c | 2 + src/http/modules/ngx_http_browser_module.c | 45 +- src/http/modules/ngx_http_fastcgi_module.c | 2 +- src/http/modules/ngx_http_geoip_module.c | 2 +- src/http/modules/ngx_http_mirror_module.c | 264 ++++++++++++ src/http/modules/ngx_http_proxy_module.c | 2 +- .../modules/ngx_http_range_filter_module.c | 4 +- src/http/modules/ngx_http_realip_module.c | 2 +- src/http/modules/ngx_http_referer_module.c | 39 +- .../modules/ngx_http_slice_filter_module.c | 10 +- src/http/modules/ngx_http_ssi_filter_module.c | 4 +- src/http/modules/ngx_http_ssl_module.c | 2 +- .../modules/ngx_http_stub_status_module.c | 2 +- src/http/modules/ngx_http_try_files_module.c | 404 ++++++++++++++++++ .../modules/ngx_http_upstream_zone_module.c | 95 +++- src/http/ngx_http.c | 21 +- src/http/ngx_http_core_module.c | 310 -------------- src/http/ngx_http_core_module.h | 18 +- src/http/ngx_http_file_cache.c | 1 + src/http/ngx_http_parse.c | 14 +- src/http/ngx_http_request.h | 1 + src/http/ngx_http_upstream.c | 16 +- src/http/ngx_http_variables.c | 2 +- src/http/ngx_http_variables.h | 2 + src/http/v2/ngx_http_v2_module.c | 2 +- src/misc/ngx_google_perftools_module.c | 2 +- src/stream/ngx_stream_geoip_module.c | 2 +- src/stream/ngx_stream_realip_module.c | 2 +- src/stream/ngx_stream_ssl_module.c | 2 +- src/stream/ngx_stream_ssl_preread_module.c | 2 +- src/stream/ngx_stream_upstream.c | 2 +- src/stream/ngx_stream_upstream_zone_module.c | 95 +++- src/stream/ngx_stream_variables.c | 2 +- src/stream/ngx_stream_variables.h | 2 + 48 files changed, 1055 insertions(+), 455 deletions(-) create mode 100644 src/http/modules/ngx_http_mirror_module.c create mode 100644 src/http/modules/ngx_http_try_files_module.c diff --git a/CHANGES b/CHANGES index 30b01ef..cc22571 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,24 @@ +Changes with nginx 1.13.4 08 Aug 2017 + + *) Feature: the ngx_http_mirror_module. + + *) Bugfix: client connections might be dropped during configuration + testing when using the "reuseport" parameter of the "listen" + directive on Linux. + + *) Bugfix: request body might not be available in subrequests if it was + saved to a file and proxying was used. + + *) Bugfix: cleaning cache based on the "max_size" parameter did not work + on Windows. + + *) Bugfix: any shared memory allocation required 4096 bytes on Windows. + + *) Bugfix: nginx worker might be terminated abnormally when using the + "zone" directive inside the "upstream" block on Windows. + + Changes with nginx 1.13.3 11 Jul 2017 *) Security: a specially crafted request might result in an integer diff --git a/CHANGES.ru b/CHANGES.ru index dab50c9..f466c4d 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,24 @@ +Изменения в nginx 1.13.4 08.08.2017 + + *) Добавление: модуль ngx_http_mirror_module. + + *) Исправление: клиентские соединения могли сбрасываться при + тестировании конфигурации, если использовался параметр reuseport + директивы listen на Linux. + + *) Исправление: тело запроса могло быть недоступно в подзапросах, если + оно было сохранено в файл и использовалось проксирование. + + *) Исправление: очистка кэша по max_size не работала на Windows. + + *) Исправление: любое выделение разделяемой памяти на Windows требовало + 4096 байт памяти. + + *) Исправление: при использовании директивы zone в блоке upstream на + Windows рабочий процесс мог завершаться аварийно. + + Изменения в nginx 1.13.3 11.07.2017 *) Безопасность: специально созданный запрос мог вызвать целочисленное diff --git a/auto/lib/conf b/auto/lib/conf index 0b8545a..2c7af10 100644 --- a/auto/lib/conf +++ b/auto/lib/conf @@ -7,7 +7,7 @@ if [ $USE_PCRE = YES -o $PCRE != NONE ]; then . auto/lib/pcre/conf else - if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then + if [ $USE_PCRE = DISABLED -a $HTTP = YES -a $HTTP_REWRITE = YES ]; then cat << END diff --git a/auto/modules b/auto/modules index be3561e..26b05bd 100644 --- a/auto/modules +++ b/auto/modules @@ -506,6 +506,28 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_MIRROR = YES ]; then + ngx_module_name=ngx_http_mirror_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_mirror_module.c + ngx_module_libs= + ngx_module_link=$HTTP_MIRROR + + . auto/module + fi + + if :; then + ngx_module_name=ngx_http_try_files_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_try_files_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module + fi + if [ $HTTP_AUTH_REQUEST = YES ]; then ngx_module_name=ngx_http_auth_request_module ngx_module_incs= diff --git a/auto/options b/auto/options index 66b822a..24c2618 100644 --- a/auto/options +++ b/auto/options @@ -70,6 +70,7 @@ HTTP_DAV=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_AUTH_REQUEST=NO +HTTP_MIRROR=YES HTTP_USERID=YES HTTP_SLICE=NO HTTP_AUTOINDEX=YES @@ -249,6 +250,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --without-http_userid_module) HTTP_USERID=NO ;; --without-http_access_module) HTTP_ACCESS=NO ;; --without-http_auth_basic_module) HTTP_AUTH_BASIC=NO ;; + --without-http_mirror_module) HTTP_MIRROR=NO ;; --without-http_autoindex_module) HTTP_AUTOINDEX=NO ;; --without-http_status_module) HTTP_STATUS=NO ;; --without-http_geo_module) HTTP_GEO=NO ;; @@ -458,6 +460,7 @@ cat << END --without-http_userid_module disable ngx_http_userid_module --without-http_access_module disable ngx_http_access_module --without-http_auth_basic_module disable ngx_http_auth_basic_module + --without-http_mirror_module disable ngx_http_mirror_module --without-http_autoindex_module disable ngx_http_autoindex_module --without-http_geo_module disable ngx_http_geo_module --without-http_map_module disable ngx_http_map_module diff --git a/src/core/nginx.c b/src/core/nginx.c index abaa50d..c3a29cc 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -273,6 +273,12 @@ main(int argc, char *const *argv) return 1; } + /* + * ngx_slab_sizes_init() requires ngx_pagesize set in ngx_os_init() + */ + + ngx_slab_sizes_init(); + if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } diff --git a/src/core/nginx.h b/src/core/nginx.h index 1f3a369..3649945 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013003 -#define NGINX_VERSION "1.13.3" +#define nginx_version 1013004 +#define NGINX_VERSION "1.13.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index ec4692b..392fc35 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -473,7 +473,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_REUSEPORT) - if (ls[i].reuseport) { + if (ls[i].reuseport && !ngx_test_config) { int reuseport; reuseport = 1; @@ -483,7 +483,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEPORT) %V failed, ignored", + "setsockopt(SO_REUSEPORT) %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { diff --git a/src/core/ngx_parse_time.c b/src/core/ngx_parse_time.c index 13afde3..a5c5034 100644 --- a/src/core/ngx_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -58,7 +58,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - day = (*p - '0') * 10 + *(p + 1) - '0'; + day = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p == ' ') { @@ -132,7 +132,7 @@ ngx_parse_http_time(u_char *value, size_t len) } year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 - + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; + + (*(p + 2) - '0') * 10 + (*(p + 3) - '0'); p += 4; } else if (fmt == rfc850) { @@ -140,7 +140,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - year = (*p - '0') * 10 + *(p + 1) - '0'; + year = (*p - '0') * 10 + (*(p + 1) - '0'); year += (year < 70) ? 2000 : 1900; p += 2; } @@ -161,7 +161,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - day = day * 10 + *p++ - '0'; + day = day * 10 + (*p++ - '0'); } if (end - p < 14) { @@ -177,7 +177,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - hour = (*p - '0') * 10 + *(p + 1) - '0'; + hour = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p++ != ':') { @@ -188,7 +188,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - min = (*p - '0') * 10 + *(p + 1) - '0'; + min = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p++ != ':') { @@ -199,7 +199,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - sec = (*p - '0') * 10 + *(p + 1) - '0'; + sec = (*p - '0') * 10 + (*(p + 1) - '0'); if (fmt == isoc) { p += 2; @@ -216,7 +216,7 @@ ngx_parse_http_time(u_char *value, size_t len) } year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 - + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; + + (*(p + 2) - '0') * 10 + (*(p + 3) - '0'); } if (hour > 23 || min > 59 || sec > 59) { diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 9e7796d..4023870 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -82,6 +82,19 @@ static ngx_uint_t ngx_slab_exact_size; static ngx_uint_t ngx_slab_exact_shift; +void +ngx_slab_sizes_init(void) +{ + ngx_uint_t n; + + ngx_slab_max_size = ngx_pagesize / 2; + ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); + for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { + /* void */ + } +} + + void ngx_slab_init(ngx_slab_pool_t *pool) { @@ -91,16 +104,6 @@ ngx_slab_init(ngx_slab_pool_t *pool) ngx_uint_t i, n, pages; ngx_slab_page_t *slots, *page; - /* STUB */ - if (ngx_slab_max_size == 0) { - ngx_slab_max_size = ngx_pagesize / 2; - ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { - /* void */ - } - } - /**/ - pool->min_size = (size_t) 1 << pool->min_shift; slots = ngx_slab_slots(pool); diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index eff893c..d1876bb 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -59,6 +59,7 @@ typedef struct { } ngx_slab_pool_t; +void ngx_slab_sizes_init(void); void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 7526f60..de10a06 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -178,7 +178,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) slen = (size_t) -1; while (*fmt >= '0' && *fmt <= '9') { - width = width * 10 + *fmt++ - '0'; + width = width * 10 + (*fmt++ - '0'); } @@ -211,7 +211,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) fmt++; while (*fmt >= '0' && *fmt <= '9') { - frac_width = frac_width * 10 + *fmt++ - '0'; + frac_width = frac_width * 10 + (*fmt++ - '0'); } break; @@ -1655,7 +1655,7 @@ ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) state = sw_usual; if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); + ch = (u_char) ((decoded << 4) + (ch - '0')); if (type & NGX_UNESCAPE_REDIRECT) { if (ch > '%' && ch < 0x7f) { @@ -1675,7 +1675,7 @@ ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); + ch = (u_char) ((decoded << 4) + (c - 'a') + 10); if (type & NGX_UNESCAPE_URI) { if (ch == '?') { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 2c4e114..07646b6 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3128,7 +3128,7 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) { if (paths) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, - "\"ssl_session_ticket_keys\" ignored, not supported"); + "\"ssl_session_ticket_key\" ignored, not supported"); } return NGX_OK; diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index d332c11..0bea5e7 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -1486,7 +1486,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) return NGX_ERROR; } - ctx->code = ctx->code * 10 + ch - '0'; + ctx->code = ctx->code * 10 + (ch - '0'); if (++ctx->count == 3) { state = sw_space_after_status; diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c index 2fad0e5..e546f0d 100644 --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -123,6 +123,8 @@ ngx_http_addition_header_filter(ngx_http_request_t *r) ngx_http_clear_accept_ranges(r); ngx_http_weak_etag(r); + r->preserve_body = 1; + return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_browser_module.c b/src/http/modules/ngx_http_browser_module.c index 80da0d8..f774254 100644 --- a/src/http/modules/ngx_http_browser_module.c +++ b/src/http/modules/ngx_http_browser_module.c @@ -37,13 +37,6 @@ typedef struct { } ngx_http_modern_browser_t; -typedef struct { - ngx_str_t name; - ngx_http_get_variable_pt handler; - uintptr_t data; -} ngx_http_browser_variable_t; - - typedef struct { ngx_array_t *modern_browsers; ngx_array_t *ancient_browsers; @@ -63,7 +56,7 @@ static ngx_int_t ngx_http_browser_variable(ngx_http_request_t *r, static ngx_uint_t ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf); -static ngx_int_t ngx_http_browser_add_variable(ngx_conf_t *cf); +static ngx_int_t ngx_http_browser_add_variables(ngx_conf_t *cf); static void *ngx_http_browser_create_conf(ngx_conf_t *cf); static char *ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -114,7 +107,7 @@ static ngx_command_t ngx_http_browser_commands[] = { static ngx_http_module_t ngx_http_browser_module_ctx = { - ngx_http_browser_add_variable, /* preconfiguration */ + ngx_http_browser_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -218,13 +211,18 @@ static ngx_http_modern_browser_mask_t ngx_http_modern_browser_masks[] = { }; -static ngx_http_browser_variable_t ngx_http_browsers[] = { - { ngx_string("msie"), ngx_http_msie_variable, 0 }, - { ngx_string("modern_browser"), ngx_http_browser_variable, - NGX_HTTP_MODERN_BROWSER }, - { ngx_string("ancient_browser"), ngx_http_browser_variable, - NGX_HTTP_ANCIENT_BROWSER }, - { ngx_null_string, NULL, 0 } +static ngx_http_variable_t ngx_http_browser_vars[] = { + + { ngx_string("msie"), NULL, ngx_http_msie_variable, + 0, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("modern_browser"), NULL, ngx_http_browser_variable, + NGX_HTTP_MODERN_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ancient_browser"), NULL, ngx_http_browser_variable, + NGX_HTTP_ANCIENT_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + ngx_http_null_variable }; @@ -397,20 +395,19 @@ ngx_http_msie_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, static ngx_int_t -ngx_http_browser_add_variable(ngx_conf_t *cf) +ngx_http_browser_add_variables(ngx_conf_t *cf) { - ngx_http_browser_variable_t *var; - ngx_http_variable_t *v; + ngx_http_variable_t *var, *v; - for (var = ngx_http_browsers; var->name.len; var++) { + for (v = ngx_http_browser_vars; v->name.len; v++) { - v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGEABLE); - if (v == NULL) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { return NGX_ERROR; } - v->get_handler = var->handler; - v->data = var->data; + var->get_handler = v->get_handler; + var->data = v->data; } return NGX_OK; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 741e577..ea16eca 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -631,7 +631,7 @@ static ngx_http_variable_t ngx_http_fastcgi_vars[] = { ngx_http_fastcgi_path_info_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index 8e151aa..5ea4f5f 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -232,7 +232,7 @@ static ngx_http_variable_t ngx_http_geoip_vars[] = { ngx_http_geoip_city_int_variable, offsetof(GeoIPRecord, area_code), 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_mirror_module.c b/src/http/modules/ngx_http_mirror_module.c new file mode 100644 index 0000000..787adb3 --- /dev/null +++ b/src/http/modules/ngx_http_mirror_module.c @@ -0,0 +1,264 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *mirror; + ngx_flag_t request_body; +} ngx_http_mirror_loc_conf_t; + + +typedef struct { + ngx_int_t status; +} ngx_http_mirror_ctx_t; + + +static ngx_int_t ngx_http_mirror_handler(ngx_http_request_t *r); +static void ngx_http_mirror_body_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_mirror_handler_internal(ngx_http_request_t *r); +static void *ngx_http_mirror_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_mirror_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_mirror_commands[] = { + + { ngx_string("mirror"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_mirror, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("mirror_request_body"), + 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_mirror_loc_conf_t, request_body), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_mirror_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_mirror_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_mirror_create_loc_conf, /* create location configuration */ + ngx_http_mirror_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_mirror_module = { + NGX_MODULE_V1, + &ngx_http_mirror_module_ctx, /* module context */ + ngx_http_mirror_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_mirror_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_mirror_ctx_t *ctx; + ngx_http_mirror_loc_conf_t *mlcf; + + if (r != r->main) { + return NGX_DECLINED; + } + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module); + + if (mlcf->mirror == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mirror handler"); + + if (mlcf->request_body) { + ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module); + + if (ctx) { + return ctx->status; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_mirror_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->status = NGX_DONE; + + ngx_http_set_ctx(r, ctx, ngx_http_mirror_module); + + rc = ngx_http_read_client_request_body(r, ngx_http_mirror_body_handler); + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + ngx_http_finalize_request(r, NGX_DONE); + return NGX_DONE; + } + + return ngx_http_mirror_handler_internal(r); +} + + +static void +ngx_http_mirror_body_handler(ngx_http_request_t *r) +{ + ngx_http_mirror_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module); + + ctx->status = ngx_http_mirror_handler_internal(r); + + r->preserve_body = 1; + + r->write_event_handler = ngx_http_core_run_phases; + ngx_http_core_run_phases(r); +} + + +static ngx_int_t +ngx_http_mirror_handler_internal(ngx_http_request_t *r) +{ + ngx_str_t *name; + ngx_uint_t i; + ngx_http_request_t *sr; + ngx_http_mirror_loc_conf_t *mlcf; + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module); + + name = mlcf->mirror->elts; + + for (i = 0; i < mlcf->mirror->nelts; i++) { + if (ngx_http_subrequest(r, &name[i], &r->args, &sr, NULL, + NGX_HTTP_SUBREQUEST_BACKGROUND) + != NGX_OK) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + sr->header_only = 1; + sr->method = r->method; + sr->method_name = r->method_name; + } + + return NGX_DECLINED; +} + + +static void * +ngx_http_mirror_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_mirror_loc_conf_t *mlcf; + + mlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mirror_loc_conf_t)); + if (mlcf == NULL) { + return NULL; + } + + mlcf->mirror = NGX_CONF_UNSET_PTR; + mlcf->request_body = NGX_CONF_UNSET; + + return mlcf; +} + + +static char * +ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_mirror_loc_conf_t *prev = parent; + ngx_http_mirror_loc_conf_t *conf = child; + + ngx_conf_merge_ptr_value(conf->mirror, prev->mirror, NULL); + ngx_conf_merge_value(conf->request_body, prev->request_body, 1); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_mirror_loc_conf_t *mlcf = conf; + + ngx_str_t *value, *s; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + if (mlcf->mirror != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + mlcf->mirror = NULL; + return NGX_CONF_OK; + } + + if (mlcf->mirror == NULL) { + return "is duplicate"; + } + + if (mlcf->mirror == NGX_CONF_UNSET_PTR) { + mlcf->mirror = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); + if (mlcf->mirror == NULL) { + return NGX_CONF_ERROR; + } + } + + s = ngx_array_push(mlcf->mirror); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + *s = value[1]; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_mirror_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_PRECONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_mirror_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 61bf55c..b42839c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -829,7 +829,7 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = { ngx_http_proxy_internal_chunked_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 292a2b8..6256b13 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -315,7 +315,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -345,7 +345,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - end = end * 10 + *p++ - '0'; + end = end * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index e1839e6..7d3f2a9 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -122,7 +122,7 @@ static ngx_http_variable_t ngx_http_realip_vars[] = { { ngx_string("realip_remote_port"), NULL, ngx_http_realip_remote_port_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c index 3f0f78e..599dd3a 100644 --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -32,6 +32,7 @@ typedef struct { } ngx_http_referer_conf_t; +static ngx_int_t ngx_http_referer_add_variables(ngx_conf_t *cf); static void * ngx_http_referer_create_conf(ngx_conf_t *cf); static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -77,7 +78,7 @@ static ngx_command_t ngx_http_referer_commands[] = { static ngx_http_module_t ngx_http_referer_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_referer_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -107,6 +108,9 @@ ngx_module_t ngx_http_referer_module = { }; +static ngx_str_t ngx_http_invalid_referer_name = ngx_string("invalid_referer"); + + static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -263,6 +267,23 @@ valid: } +static ngx_int_t +ngx_http_referer_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var; + + var = ngx_http_add_variable(cf, &ngx_http_invalid_referer_name, + NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = ngx_http_referer_variable; + + return NGX_OK; +} + + static void * ngx_http_referer_create_conf(ngx_conf_t *cf) { @@ -452,19 +473,9 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_referer_conf_t *rlcf = conf; - u_char *p; - ngx_str_t *value, uri, name; - ngx_uint_t i; - ngx_http_variable_t *var; - - ngx_str_set(&name, "invalid_referer"); - - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->get_handler = ngx_http_referer_variable; + u_char *p; + ngx_str_t *value, uri; + ngx_uint_t i; if (rlcf->keys == NULL) { rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c index 7758342..c1edbca 100644 --- a/src/http/modules/ngx_http_slice_filter_module.c +++ b/src/http/modules/ngx_http_slice_filter_module.c @@ -190,6 +190,8 @@ ngx_http_slice_header_filter(ngx_http_request_t *r) return rc; } + r->preserve_body = 1; + if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { ctx->start = slcf->size @@ -317,7 +319,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -337,7 +339,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - end = end * 10 + *p++ - '0'; + end = end * 10 + (*p++ - '0'); } end++; @@ -362,7 +364,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - complete_length = complete_length * 10 + *p++ - '0'; + complete_length = complete_length * 10 + (*p++ - '0'); } } else { @@ -479,7 +481,7 @@ ngx_http_slice_get_start(ngx_http_request_t *r) return 0; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } return start; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index b92ad4c..e29e173 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -321,7 +321,7 @@ static ngx_http_variable_t ngx_http_ssi_vars[] = { { ngx_string("date_gmt"), NULL, ngx_http_ssi_date_gmt_local_variable, 1, NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -370,6 +370,8 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); + r->preserve_body = 1; + if (!slcf->last_modified) { ngx_http_clear_last_modified(r); ngx_http_clear_etag(r); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index b466e5d..4370275 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -329,7 +329,7 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index 61199f2..9bdf881 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -76,7 +76,7 @@ static ngx_http_variable_t ngx_http_stub_status_vars[] = { { ngx_string("connections_waiting"), NULL, ngx_http_stub_status_variable, 3, NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_try_files_module.c b/src/http/modules/ngx_http_try_files_module.c new file mode 100644 index 0000000..ce783a2 --- /dev/null +++ b/src/http/modules/ngx_http_try_files_module.c @@ -0,0 +1,404 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; + ngx_str_t name; + + unsigned code:10; + unsigned test_dir:1; +} ngx_http_try_file_t; + + +typedef struct { + ngx_http_try_file_t *try_files; +} ngx_http_try_files_loc_conf_t; + + +static ngx_int_t ngx_http_try_files_handler(ngx_http_request_t *r); +static char *ngx_http_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void *ngx_http_try_files_create_loc_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_try_files_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_try_files_commands[] = { + + { ngx_string("try_files"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + ngx_http_try_files, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_try_files_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_try_files_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_try_files_create_loc_conf, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_try_files_module = { + NGX_MODULE_V1, + &ngx_http_try_files_module_ctx, /* module context */ + ngx_http_try_files_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_try_files_handler(ngx_http_request_t *r) +{ + size_t len, root, alias, reserve, allocated; + u_char *p, *name; + ngx_str_t path, args; + ngx_uint_t test_dir; + ngx_http_try_file_t *tf; + ngx_open_file_info_t of; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e; + ngx_http_core_loc_conf_t *clcf; + ngx_http_script_len_code_pt lcode; + ngx_http_try_files_loc_conf_t *tlcf; + + tlcf = ngx_http_get_module_loc_conf(r, ngx_http_try_files_module); + + if (tlcf->try_files == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try files handler"); + + allocated = 0; + root = 0; + name = NULL; + /* suppress MSVC warning */ + path.data = NULL; + + tf = tlcf->try_files; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + alias = clcf->alias; + + for ( ;; ) { + + if (tf->lengths) { + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + e.ip = tf->lengths->elts; + e.request = r; + + /* 1 is for terminating '\0' as in static names */ + len = 1; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + } else { + len = tf->name.len; + } + + if (!alias) { + reserve = len > r->uri.len ? len - r->uri.len : 0; + + } else if (alias == NGX_MAX_SIZE_T_VALUE) { + reserve = len; + + } else { + reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; + } + + if (reserve > allocated || !allocated) { + + /* 16 bytes are preallocation */ + allocated = reserve + 16; + + if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + name = path.data + root; + } + + if (tf->values == NULL) { + + /* tf->name.len includes the terminating '\0' */ + + ngx_memcpy(name, tf->name.data, tf->name.len); + + path.len = (name + tf->name.len - 1) - path.data; + + } else { + e.ip = tf->values->elts; + e.pos = name; + e.flushed = 1; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + + path.len = e.pos - path.data; + + *e.pos = '\0'; + + if (alias && alias != NGX_MAX_SIZE_T_VALUE + && ngx_strncmp(name, r->uri.data, alias) == 0) + { + ngx_memmove(name, name + alias, len - alias); + path.len -= alias; + } + } + + test_dir = tf->test_dir; + + tf++; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "trying to use %s: \"%s\" \"%s\"", + test_dir ? "dir" : "file", name, path.data); + + if (tf->lengths == NULL && tf->name.len == 0) { + + if (tf->code) { + return tf->code; + } + + path.len -= root; + path.data += root; + + if (path.data[0] == '@') { + (void) ngx_http_named_location(r, &path); + + } else { + ngx_http_split_args(r, &path, &args); + + (void) ngx_http_internal_redirect(r, &path, &args); + } + + ngx_http_finalize_request(r, NGX_DONE); + return NGX_DONE; + } + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.read_ahead = clcf->read_ahead; + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.test_only = 1; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { + if (of.err == 0) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (of.err != NGX_ENOENT + && of.err != NGX_ENOTDIR + && of.err != NGX_ENAMETOOLONG) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, + "%s \"%s\" failed", of.failed, path.data); + } + + continue; + } + + if (of.is_dir != test_dir) { + continue; + } + + path.len -= root; + path.data += root; + + if (!alias) { + r->uri = path; + + } else if (alias == NGX_MAX_SIZE_T_VALUE) { + if (!test_dir) { + r->uri = path; + r->add_uri_to_alias = 1; + } + + } else { + name = r->uri.data; + + r->uri.len = alias + path.len; + r->uri.data = ngx_pnalloc(r->pool, r->uri.len); + if (r->uri.data == NULL) { + r->uri.len = 0; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = ngx_copy(r->uri.data, name, alias); + ngx_memcpy(p, path.data, path.len); + } + + ngx_http_set_exten(r); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try file uri: \"%V\"", &r->uri); + + return NGX_DECLINED; + } + + /* not reached */ +} + + +static char * +ngx_http_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_try_files_loc_conf_t *tlcf = conf; + + ngx_str_t *value; + ngx_int_t code; + ngx_uint_t i, n; + ngx_http_try_file_t *tf; + ngx_http_script_compile_t sc; + + if (tlcf->try_files) { + return "is duplicate"; + } + + tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t)); + if (tf == NULL) { + return NGX_CONF_ERROR; + } + + tlcf->try_files = tf; + + value = cf->args->elts; + + for (i = 0; i < cf->args->nelts - 1; i++) { + + tf[i].name = value[i + 1]; + + if (tf[i].name.len > 0 + && tf[i].name.data[tf[i].name.len - 1] == '/' + && i + 2 < cf->args->nelts) + { + tf[i].test_dir = 1; + tf[i].name.len--; + tf[i].name.data[tf[i].name.len] = '\0'; + } + + n = ngx_http_script_variables_count(&tf[i].name); + + if (n) { + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &tf[i].name; + sc.lengths = &tf[i].lengths; + sc.values = &tf[i].values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + /* add trailing '\0' to length */ + tf[i].name.len++; + } + } + + if (tf[i - 1].name.data[0] == '=') { + + code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); + + if (code == NGX_ERROR || code > 999) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid code \"%*s\"", + tf[i - 1].name.len - 1, tf[i - 1].name.data); + return NGX_CONF_ERROR; + } + + tf[i].code = code; + } + + return NGX_CONF_OK; +} + + +static void * +ngx_http_try_files_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_try_files_loc_conf_t *tlcf; + + tlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_try_files_loc_conf_t)); + if (tlcf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * tlcf->try_files = NULL; + */ + + return tlcf; +} + + +static ngx_int_t +ngx_http_try_files_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_PRECONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_try_files_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index 7e5bd74..d340b48 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); static ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers( ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf); +static ngx_http_upstream_rr_peer_t *ngx_http_upstream_zone_copy_peer( + ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *src); static ngx_command_t ngx_http_upstream_zone_commands[] = { @@ -185,6 +187,7 @@ static ngx_http_upstream_rr_peers_t * ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf) { + ngx_str_t *name; ngx_http_upstream_rr_peer_t *peer, **peerp; ngx_http_upstream_rr_peers_t *peers, *backup; @@ -195,18 +198,30 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t)); + name = ngx_slab_alloc(shpool, sizeof(ngx_str_t)); + if (name == NULL) { + return NULL; + } + + name->data = ngx_slab_alloc(shpool, peers->name->len); + if (name->data == NULL) { + return NULL; + } + + ngx_memcpy(name->data, peers->name->data, peers->name->len); + name->len = peers->name->len; + + peers->name = name; + peers->shpool = shpool; for (peerp = &peers->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_http_upstream_rr_peer_t)); + peer = ngx_http_upstream_zone_copy_peer(peers, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); - *peerp = peer; } @@ -221,18 +236,17 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t)); + backup->name = name; + backup->shpool = shpool; for (peerp = &backup->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_http_upstream_rr_peer_t)); + peer = ngx_http_upstream_zone_copy_peer(backup, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); - *peerp = peer; } @@ -244,3 +258,68 @@ done: return peers; } + + +static ngx_http_upstream_rr_peer_t * +ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers, + ngx_http_upstream_rr_peer_t *src) +{ + ngx_slab_pool_t *pool; + ngx_http_upstream_rr_peer_t *dst; + + pool = peers->shpool; + + dst = ngx_slab_calloc_locked(pool, sizeof(ngx_http_upstream_rr_peer_t)); + if (dst == NULL) { + return NULL; + } + + if (src) { + ngx_memcpy(dst, src, sizeof(ngx_http_upstream_rr_peer_t)); + dst->sockaddr = NULL; + dst->name.data = NULL; + dst->server.data = NULL; + } + + dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + if (dst->sockaddr == NULL) { + goto failed; + } + + dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN); + if (dst->name.data == NULL) { + goto failed; + } + + if (src) { + ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen); + ngx_memcpy(dst->name.data, src->name.data, src->name.len); + + dst->server.data = ngx_slab_alloc_locked(pool, src->server.len); + if (dst->server.data == NULL) { + goto failed; + } + + ngx_memcpy(dst->server.data, src->server.data, src->server.len); + } + + return dst; + +failed: + + if (dst->server.data) { + ngx_slab_free_locked(pool, dst->server.data); + } + + if (dst->name.data) { + ngx_slab_free_locked(pool, dst->name.data); + } + + if (dst->sockaddr) { + ngx_slab_free_locked(pool, dst->sockaddr); + } + + ngx_slab_free_locked(pool, dst); + + return NULL; +} diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index c036389..9d8b6d7 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -382,6 +382,13 @@ ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) return NGX_ERROR; } + if (ngx_array_init(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers, + cf->pool, 2, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, cf->pool, 4, sizeof(ngx_http_handler_pt)) != NGX_OK) @@ -459,8 +466,7 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) n = 1 /* find config phase */ + use_rewrite /* post rewrite phase */ - + use_access /* post access phase */ - + cmcf->try_files; + + use_access; /* post access phase */ for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { n += cmcf->phases[i].handlers.nelts; @@ -529,15 +535,6 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) continue; - case NGX_HTTP_TRY_FILES_PHASE: - if (cmcf->try_files) { - ph->checker = ngx_http_core_try_files_phase; - n++; - ph++; - } - - continue; - case NGX_HTTP_CONTENT_PHASE: checker = ngx_http_core_content_phase; break; @@ -548,7 +545,7 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) n += cmcf->phases[i].handlers.nelts; - for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) { + for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) { ph->checker = checker; ph->handler = h[j]; ph->next = n; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 02059ef..57a4742 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -61,8 +61,6 @@ static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, @@ -649,13 +647,6 @@ static ngx_command_t ngx_http_core_commands[] = { 0, NULL }, - { ngx_string("try_files"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, - ngx_http_core_try_files, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - { ngx_string("post_action"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -1158,223 +1149,6 @@ ngx_http_core_post_access_phase(ngx_http_request_t *r, } -ngx_int_t -ngx_http_core_try_files_phase(ngx_http_request_t *r, - ngx_http_phase_handler_t *ph) -{ - size_t len, root, alias, reserve, allocated; - u_char *p, *name; - ngx_str_t path, args; - ngx_uint_t test_dir; - ngx_http_try_file_t *tf; - ngx_open_file_info_t of; - ngx_http_script_code_pt code; - ngx_http_script_engine_t e; - ngx_http_core_loc_conf_t *clcf; - ngx_http_script_len_code_pt lcode; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try files phase: %ui", r->phase_handler); - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->try_files == NULL) { - r->phase_handler++; - return NGX_AGAIN; - } - - allocated = 0; - root = 0; - name = NULL; - /* suppress MSVC warning */ - path.data = NULL; - - tf = clcf->try_files; - - alias = clcf->alias; - - for ( ;; ) { - - if (tf->lengths) { - ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - - e.ip = tf->lengths->elts; - e.request = r; - - /* 1 is for terminating '\0' as in static names */ - len = 1; - - while (*(uintptr_t *) e.ip) { - lcode = *(ngx_http_script_len_code_pt *) e.ip; - len += lcode(&e); - } - - } else { - len = tf->name.len; - } - - if (!alias) { - reserve = len > r->uri.len ? len - r->uri.len : 0; - - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - reserve = len; - - } else { - reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; - } - - if (reserve > allocated || !allocated) { - - /* 16 bytes are preallocation */ - allocated = reserve + 16; - - if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - name = path.data + root; - } - - if (tf->values == NULL) { - - /* tf->name.len includes the terminating '\0' */ - - ngx_memcpy(name, tf->name.data, tf->name.len); - - path.len = (name + tf->name.len - 1) - path.data; - - } else { - e.ip = tf->values->elts; - e.pos = name; - e.flushed = 1; - - while (*(uintptr_t *) e.ip) { - code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) &e); - } - - path.len = e.pos - path.data; - - *e.pos = '\0'; - - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_strncmp(name, r->uri.data, alias) == 0) - { - ngx_memmove(name, name + alias, len - alias); - path.len -= alias; - } - } - - test_dir = tf->test_dir; - - tf++; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "trying to use %s: \"%s\" \"%s\"", - test_dir ? "dir" : "file", name, path.data); - - if (tf->lengths == NULL && tf->name.len == 0) { - - if (tf->code) { - ngx_http_finalize_request(r, tf->code); - return NGX_OK; - } - - path.len -= root; - path.data += root; - - if (path.data[0] == '@') { - (void) ngx_http_named_location(r, &path); - - } else { - ngx_http_split_args(r, &path, &args); - - (void) ngx_http_internal_redirect(r, &path, &args); - } - - ngx_http_finalize_request(r, NGX_DONE); - return NGX_OK; - } - - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - - of.read_ahead = clcf->read_ahead; - of.directio = clcf->directio; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.test_only = 1; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; - - if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) - != NGX_OK) - { - if (of.err == 0) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - if (of.err != NGX_ENOENT - && of.err != NGX_ENOTDIR - && of.err != NGX_ENAMETOOLONG) - { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - "%s \"%s\" failed", of.failed, path.data); - } - - continue; - } - - if (of.is_dir != test_dir) { - continue; - } - - path.len -= root; - path.data += root; - - if (!alias) { - r->uri = path; - - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!test_dir) { - r->uri = path; - r->add_uri_to_alias = 1; - } - - } else { - name = r->uri.data; - - r->uri.len = alias + path.len; - r->uri.data = ngx_pnalloc(r->pool, r->uri.len); - if (r->uri.data == NULL) { - r->uri.len = 0; - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - p = ngx_copy(r->uri.data, name, alias); - ngx_memcpy(p, path.data, path.len); - } - - ngx_http_set_exten(r); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try file uri: \"%V\"", &r->uri); - - r->phase_handler++; - return NGX_AGAIN; - } - - /* not reached */ -} - - ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) @@ -3561,7 +3335,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * clcf->default_type = { 0, NULL }; * clcf->error_log = NULL; * clcf->error_pages = NULL; - * clcf->try_files = NULL; * clcf->client_body_path = NULL; * clcf->regex = NULL; * clcf->exact_match = 0; @@ -4884,89 +4657,6 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } -static char * -ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_core_loc_conf_t *clcf = conf; - - ngx_str_t *value; - ngx_int_t code; - ngx_uint_t i, n; - ngx_http_try_file_t *tf; - ngx_http_script_compile_t sc; - ngx_http_core_main_conf_t *cmcf; - - if (clcf->try_files) { - return "is duplicate"; - } - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - cmcf->try_files = 1; - - tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t)); - if (tf == NULL) { - return NGX_CONF_ERROR; - } - - clcf->try_files = tf; - - value = cf->args->elts; - - for (i = 0; i < cf->args->nelts - 1; i++) { - - tf[i].name = value[i + 1]; - - if (tf[i].name.len > 0 - && tf[i].name.data[tf[i].name.len - 1] == '/' - && i + 2 < cf->args->nelts) - { - tf[i].test_dir = 1; - tf[i].name.len--; - tf[i].name.data[tf[i].name.len] = '\0'; - } - - n = ngx_http_script_variables_count(&tf[i].name); - - if (n) { - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &tf[i].name; - sc.lengths = &tf[i].lengths; - sc.values = &tf[i].values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; - } - - } else { - /* add trailing '\0' to length */ - tf[i].name.len++; - } - } - - if (tf[i - 1].name.data[0] == '=') { - - code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); - - if (code == NGX_ERROR || code > 999) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid code \"%*s\"", - tf[i - 1].name.len - 1, tf[i - 1].name.data); - return NGX_CONF_ERROR; - } - - tf[i].code = code; - } - - return NGX_CONF_OK; -} - - static char * ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 5018da0..a6128b5 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -119,7 +119,8 @@ typedef enum { NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, - NGX_HTTP_TRY_FILES_PHASE, + NGX_HTTP_PRECONTENT_PHASE, + NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE @@ -172,8 +173,6 @@ typedef struct { ngx_array_t *ports; - ngx_uint_t try_files; /* unsigned try_files:1 */ - ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1]; } ngx_http_core_main_conf_t; @@ -296,16 +295,6 @@ typedef struct { } ngx_http_err_page_t; -typedef struct { - ngx_array_t *lengths; - ngx_array_t *values; - ngx_str_t name; - - unsigned code:10; - unsigned test_dir:1; -} ngx_http_try_file_t; - - struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ @@ -425,7 +414,6 @@ struct ngx_http_core_loc_conf_s { #endif ngx_array_t *error_pages; /* error_page */ - ngx_http_try_file_t *try_files; /* try_files */ ngx_path_t *client_body_temp_path; /* client_body_temp_path */ @@ -486,8 +474,6 @@ ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); -ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r, - ngx_http_phase_handler_t *ph); ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index a823c51..3b2b68a 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -129,6 +129,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) if (shm_zone->shm.exists) { cache->sh = cache->shpool->data; cache->bsize = ngx_fs_bsize(cache->path->name.data); + cache->max_size /= cache->bsize; return NGX_OK; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index e8e5156..844054c 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -742,7 +742,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - r->http_major = r->http_major * 10 + ch - '0'; + r->http_major = r->http_major * 10 + (ch - '0'); if (r->http_major > 1) { return NGX_HTTP_PARSE_INVALID_VERSION; @@ -784,7 +784,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - r->http_minor = r->http_minor * 10 + ch - '0'; + r->http_minor = r->http_minor * 10 + (ch - '0'); break; case sw_spaces_after_digit: @@ -1518,7 +1518,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_quoted_second: if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); + ch = (u_char) ((decoded << 4) + (ch - '0')); if (ch == '%' || ch == '#') { state = sw_usual; @@ -1536,7 +1536,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); + ch = (u_char) ((decoded << 4) + (c - 'a') + 10); if (ch == '?') { state = sw_usual; @@ -1701,7 +1701,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - r->http_major = r->http_major * 10 + ch - '0'; + r->http_major = r->http_major * 10 + (ch - '0'); break; /* the first digit of minor HTTP version */ @@ -1729,7 +1729,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - r->http_minor = r->http_minor * 10 + ch - '0'; + r->http_minor = r->http_minor * 10 + (ch - '0'); break; /* HTTP status code */ @@ -1742,7 +1742,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - status->code = status->code * 10 + ch - '0'; + status->code = status->code * 10 + (ch - '0'); if (++status->count == 3) { state = sw_space_after_status; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index f7f3e97..421004a 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -537,6 +537,7 @@ struct ngx_http_request_s { unsigned main_filter_need_in_memory:1; unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; + unsigned preserve_body:1; unsigned allow_ranges:1; unsigned subrequest_ranges:1; unsigned single_range:1; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index c394b29..6a2b322 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -427,7 +427,7 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { { ngx_string("upstream_cookie_"), NULL, ngx_http_upstream_cookie_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -1077,6 +1077,10 @@ ngx_http_upstream_cache_background_update(ngx_http_request_t *r, return NGX_OK; } + if (r == r->main) { + r->preserve_body = 1; + } + if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, NGX_HTTP_SUBREQUEST_CLONE |NGX_HTTP_SUBREQUEST_BACKGROUND) @@ -2857,7 +2861,9 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->pipe->downstream_error = 1; } - if (r->request_body && r->request_body->temp_file) { + if (r->request_body && r->request_body->temp_file + && r == r->main && !r->preserve_body) + { ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd); r->request_body->temp_file->file.fd = NGX_INVALID_FILE; } @@ -4503,7 +4509,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } @@ -4531,7 +4537,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } @@ -4554,7 +4560,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index fbc9ffa..afeb4ce 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -376,7 +376,7 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("arg_"), NULL, ngx_http_variable_argument, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h index df337de..f3f7f3c 100644 --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -43,6 +43,8 @@ struct ngx_http_variable_s { ngx_uint_t index; }; +#define ngx_http_null_variable { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags); diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 032abcb..7f7dab2 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -225,7 +225,7 @@ static ngx_http_variable_t ngx_http_v2_vars[] = { { ngx_string("http2"), NULL, ngx_http_v2_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/misc/ngx_google_perftools_module.c b/src/misc/ngx_google_perftools_module.c index f2f8221..381f3d1 100644 --- a/src/misc/ngx_google_perftools_module.c +++ b/src/misc/ngx_google_perftools_module.c @@ -36,7 +36,7 @@ static ngx_command_t ngx_google_perftools_commands[] = { offsetof(ngx_google_perftools_conf_t, profiles), NULL }, - ngx_null_command + ngx_null_command }; diff --git a/src/stream/ngx_stream_geoip_module.c b/src/stream/ngx_stream_geoip_module.c index f694033..6507b71 100644 --- a/src/stream/ngx_stream_geoip_module.c +++ b/src/stream/ngx_stream_geoip_module.c @@ -210,7 +210,7 @@ static ngx_stream_variable_t ngx_stream_geoip_vars[] = { ngx_stream_geoip_city_int_variable, offsetof(GeoIPRecord, area_code), 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c index 1266605..57b1ac2 100644 --- a/src/stream/ngx_stream_realip_module.c +++ b/src/stream/ngx_stream_realip_module.c @@ -89,7 +89,7 @@ static ngx_stream_variable_t ngx_stream_realip_vars[] = { { ngx_string("realip_remote_port"), NULL, ngx_stream_realip_remote_port_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index da26a41..010b98b 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -273,7 +273,7 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c index 2040b4f..e3d11fd 100644 --- a/src/stream/ngx_stream_ssl_preread_module.c +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -85,7 +85,7 @@ static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = { { ngx_string("ssl_preread_server_name"), NULL, ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index c9e1784..7feac43 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -100,7 +100,7 @@ static ngx_stream_variable_t ngx_stream_upstream_vars[] = { ngx_stream_upstream_bytes_variable, 1, NGX_STREAM_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 07ab88d..4f72188 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); static ngx_stream_upstream_rr_peers_t *ngx_stream_upstream_zone_copy_peers( ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf); +static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_zone_copy_peer( + ngx_stream_upstream_rr_peers_t *peers, ngx_stream_upstream_rr_peer_t *src); static ngx_command_t ngx_stream_upstream_zone_commands[] = { @@ -182,6 +184,7 @@ static ngx_stream_upstream_rr_peers_t * ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf) { + ngx_str_t *name; ngx_stream_upstream_rr_peer_t *peer, **peerp; ngx_stream_upstream_rr_peers_t *peers, *backup; @@ -192,18 +195,30 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_stream_upstream_rr_peers_t)); + name = ngx_slab_alloc(shpool, sizeof(ngx_str_t)); + if (name == NULL) { + return NULL; + } + + name->data = ngx_slab_alloc(shpool, peers->name->len); + if (name->data == NULL) { + return NULL; + } + + ngx_memcpy(name->data, peers->name->data, peers->name->len); + name->len = peers->name->len; + + peers->name = name; + peers->shpool = shpool; for (peerp = &peers->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_stream_upstream_rr_peer_t)); + peer = ngx_stream_upstream_zone_copy_peer(peers, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); - *peerp = peer; } @@ -218,18 +233,17 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(backup, peers->next, sizeof(ngx_stream_upstream_rr_peers_t)); + backup->name = name; + backup->shpool = shpool; for (peerp = &backup->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_stream_upstream_rr_peer_t)); + peer = ngx_stream_upstream_zone_copy_peer(backup, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); - *peerp = peer; } @@ -241,3 +255,68 @@ done: return peers; } + + +static ngx_stream_upstream_rr_peer_t * +ngx_stream_upstream_zone_copy_peer(ngx_stream_upstream_rr_peers_t *peers, + ngx_stream_upstream_rr_peer_t *src) +{ + ngx_slab_pool_t *pool; + ngx_stream_upstream_rr_peer_t *dst; + + pool = peers->shpool; + + dst = ngx_slab_calloc_locked(pool, sizeof(ngx_stream_upstream_rr_peer_t)); + if (dst == NULL) { + return NULL; + } + + if (src) { + ngx_memcpy(dst, src, sizeof(ngx_stream_upstream_rr_peer_t)); + dst->sockaddr = NULL; + dst->name.data = NULL; + dst->server.data = NULL; + } + + dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + if (dst->sockaddr == NULL) { + goto failed; + } + + dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN); + if (dst->name.data == NULL) { + goto failed; + } + + if (src) { + ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen); + ngx_memcpy(dst->name.data, src->name.data, src->name.len); + + dst->server.data = ngx_slab_alloc_locked(pool, src->server.len); + if (dst->server.data == NULL) { + goto failed; + } + + ngx_memcpy(dst->server.data, src->server.data, src->server.len); + } + + return dst; + +failed: + + if (dst->server.data) { + ngx_slab_free_locked(pool, dst->server.data); + } + + if (dst->name.data) { + ngx_slab_free_locked(pool, dst->name.data); + } + + if (dst->sockaddr) { + ngx_slab_free_locked(pool, dst->sockaddr); + } + + ngx_slab_free_locked(pool, dst); + + return NULL; +} diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 5d15f3a..45d6e60 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -111,7 +111,7 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { { ngx_string("protocol"), NULL, ngx_stream_variable_protocol, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_variables.h b/src/stream/ngx_stream_variables.h index 8155111..4ead2a6 100644 --- a/src/stream/ngx_stream_variables.h +++ b/src/stream/ngx_stream_variables.h @@ -43,6 +43,8 @@ struct ngx_stream_variable_s { ngx_uint_t index; }; +#define ngx_stream_null_variable { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_variable_t *ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags); From ef8a520c389d205a8e72414aedb4fe133161f41e Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 14:43:20 +0300 Subject: [PATCH 018/414] Add a simple lua autopkgtest --- debian/tests/control | 4 ++++ debian/tests/lua | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 debian/tests/lua diff --git a/debian/tests/control b/debian/tests/control index d276e4f..b491482 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -6,6 +6,10 @@ Tests: ec-x25519 Restrictions: allow-stderr isolation-container needs-root Depends: nginx-light, ssl-cert, curl +Tests: lua +Restrictions: allow-stderr isolation-container needs-root +Depends: nginx-extras, curl + Tests: full-simple Restrictions: allow-stderr isolation-container Depends: nginx-full, curl diff --git a/debian/tests/lua b/debian/tests/lua new file mode 100644 index 0000000..396d8a9 --- /dev/null +++ b/debian/tests/lua @@ -0,0 +1,18 @@ +#!/bin/bash + +set -e + +rm /etc/nginx/sites-enabled/default +cat < "/etc/nginx/sites-enabled/lua" +server { + listen 80 default_server; + + location /ping { + content_by_lua 'ngx.say("PONG")'; + } +} +EOF + +nginx -t +nginx -s reload +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ping From 2a34dcb90fc48ecf0d078d6b34132dacbe387ce2 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 13:50:13 +0300 Subject: [PATCH 019/414] Discover LuaJIT 2.1 (FTBFS) Closes: #873319 --- debian/modules/README.Modules-versions | 1 + .../nginx-lua/discover-luajit-2.1.patch | 47 +++++++++++++++++++ debian/modules/patches/nginx-lua/series | 1 + 3 files changed, 49 insertions(+) create mode 100644 debian/modules/patches/nginx-lua/discover-luajit-2.1.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index c336064..ef2bb91 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -26,6 +26,7 @@ README for Modules versions Version: v0.10.7 Patch: openssl-1.1.0.patch Patch: build-nginx-1.11.11.patch + Patch: discover-luajit-2.1.patch nginx-upstream-fair Homepage: https://github.com/gnosek/nginx-upstream-fair diff --git a/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch b/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch new file mode 100644 index 0000000..4fcbbac --- /dev/null +++ b/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch @@ -0,0 +1,47 @@ +From 0bb37a210d165870f7c4c9ad85e1751bdc1aec8f Mon Sep 17 00:00:00 2001 +From: Christos Trochalakis +Date: Mon, 28 Aug 2017 13:48:08 +0300 +Subject: [PATCH] Inventorize LuaJIT 2.1 + +--- + config | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/config b/config +index 01a6b3c3..5819c00f 100644 +--- a/config ++++ b/config +@@ -281,6 +281,30 @@ END + fi + . auto/feature + fi ++ ++ if [ $ngx_found = no ]; then ++ # LuaJIT-2.1, try with -ldl ++ ngx_feature="LuaJIT 2.1 library in /usr/" ++ ngx_feature_path="/usr/include/luajit-2.1" ++ if [ $NGX_RPATH = YES ]; then ++ ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1 -ldl" ++ else ++ ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1 -ldl" ++ fi ++ . auto/feature ++ fi ++ ++ if [ $ngx_found = no ]; then ++ # Gentoo with LuaJIT 2.1 ++ ngx_feature="LuaJIT library in /usr/" ++ ngx_feature_path="/usr/include/luajit-2.1" ++ if [ $NGX_RPATH = YES ]; then ++ ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1" ++ else ++ ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1" ++ fi ++ . auto/feature ++ fi + fi + fi + +-- +2.14.1 + diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/nginx-lua/series index bf7b34f..8edeaf5 100644 --- a/debian/modules/patches/nginx-lua/series +++ b/debian/modules/patches/nginx-lua/series @@ -1,2 +1,3 @@ openssl-1.1.0.patch build-nginx-1.1.11.patch +discover-luajit-2.1.patch From 75a3ff5eaa1d1708d6c89940a36506860d5fbbbd Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 15:08:10 +0300 Subject: [PATCH 020/414] Update nginx-lua to v0.10.10 Fixes an issue with LuaJIT v2.1, luaL_getn() is no longer available. --- debian/modules/README.Modules-versions | 2 +- debian/modules/nginx-lua/README.markdown | 275 ++++++--- debian/modules/nginx-lua/config | 29 +- .../modules/nginx-lua/doc/HttpLuaModule.wiki | 415 ++++++++----- .../nginx-lua/src/api/ngx_http_lua_api.h | 2 +- .../modules/nginx-lua/src/ngx_http_lua_api.c | 7 +- .../modules/nginx-lua/src/ngx_http_lua_args.c | 2 +- .../nginx-lua/src/ngx_http_lua_balancer.c | 15 +- .../nginx-lua/src/ngx_http_lua_common.h | 27 +- .../nginx-lua/src/ngx_http_lua_control.c | 4 +- .../nginx-lua/src/ngx_http_lua_directive.c | 67 ++ .../nginx-lua/src/ngx_http_lua_directive.h | 3 +- .../nginx-lua/src/ngx_http_lua_headers.c | 124 +++- .../nginx-lua/src/ngx_http_lua_headers.h | 3 + .../modules/nginx-lua/src/ngx_http_lua_log.c | 117 ++++ .../modules/nginx-lua/src/ngx_http_lua_log.h | 4 + .../nginx-lua/src/ngx_http_lua_log_ringbuf.c | 225 +++++++ .../nginx-lua/src/ngx_http_lua_log_ringbuf.h | 31 + .../nginx-lua/src/ngx_http_lua_module.c | 70 +-- .../nginx-lua/src/ngx_http_lua_regex.c | 82 ++- .../nginx-lua/src/ngx_http_lua_regex.h | 2 + .../nginx-lua/src/ngx_http_lua_semaphore.c | 11 +- .../nginx-lua/src/ngx_http_lua_sleep.c | 30 +- .../nginx-lua/src/ngx_http_lua_socket_tcp.c | 25 +- .../modules/nginx-lua/src/ngx_http_lua_ssl.h | 6 +- .../nginx-lua/src/ngx_http_lua_ssl_certby.c | 27 +- .../nginx-lua/src/ngx_http_lua_ssl_ocsp.c | 1 - .../src/ngx_http_lua_ssl_session_fetchby.c | 14 +- .../src/ngx_http_lua_ssl_session_storeby.c | 8 +- .../nginx-lua/src/ngx_http_lua_string.c | 9 +- .../nginx-lua/src/ngx_http_lua_timer.c | 209 ++++++- .../modules/nginx-lua/src/ngx_http_lua_util.c | 52 +- .../nginx-lua/src/ngx_http_lua_worker.c | 45 ++ debian/modules/nginx-lua/t/000--init.t | 1 - debian/modules/nginx-lua/t/000-sanity.t | 1 - debian/modules/nginx-lua/t/001-set.t | 1 - debian/modules/nginx-lua/t/002-content.t | 1 - debian/modules/nginx-lua/t/003-errors.t | 1 - debian/modules/nginx-lua/t/004-require.t | 1 - debian/modules/nginx-lua/t/005-exit.t | 1 - debian/modules/nginx-lua/t/006-escape.t | 20 +- debian/modules/nginx-lua/t/007-md5.t | 1 - debian/modules/nginx-lua/t/008-today.t | 1 - debian/modules/nginx-lua/t/009-log.t | 1 - debian/modules/nginx-lua/t/010-request_body.t | 1 - debian/modules/nginx-lua/t/012-now.t | 1 - debian/modules/nginx-lua/t/014-bugs.t | 3 +- debian/modules/nginx-lua/t/016-resp-header.t | 70 ++- debian/modules/nginx-lua/t/017-exec.t | 1 - debian/modules/nginx-lua/t/018-ndk.t | 1 - debian/modules/nginx-lua/t/019-const.t | 1 - debian/modules/nginx-lua/t/021-cookie-time.t | 1 - debian/modules/nginx-lua/t/022-redirect.t | 53 +- .../nginx-lua/t/023-rewrite/client-abort.t | 1 - debian/modules/nginx-lua/t/023-rewrite/exec.t | 1 - debian/modules/nginx-lua/t/023-rewrite/exit.t | 1 - .../modules/nginx-lua/t/023-rewrite/mixed.t | 1 - .../nginx-lua/t/023-rewrite/multi-capture.t | 1 - .../nginx-lua/t/023-rewrite/on-abort.t | 1 - .../nginx-lua/t/023-rewrite/redirect.t | 1 - .../nginx-lua/t/023-rewrite/req-body.t | 1 - .../nginx-lua/t/023-rewrite/req-socket.t | 1 - .../nginx-lua/t/023-rewrite/request_body.t | 1 - .../modules/nginx-lua/t/023-rewrite/sanity.t | 1 - .../modules/nginx-lua/t/023-rewrite/sleep.t | 1 - .../t/023-rewrite/socket-keepalive.t | 1 - .../nginx-lua/t/023-rewrite/subrequest.t | 1 - .../t/023-rewrite/tcp-socket-timeout.t | 29 +- .../nginx-lua/t/023-rewrite/tcp-socket.t | 9 +- .../nginx-lua/t/023-rewrite/unix-socket.t | 1 - .../t/023-rewrite/uthread-redirect.t | 1 - .../nginx-lua/t/023-rewrite/uthread-spawn.t | 1 - debian/modules/nginx-lua/t/024-access/auth.t | 1 - .../nginx-lua/t/024-access/client-abort.t | 1 - debian/modules/nginx-lua/t/024-access/exit.t | 1 - .../nginx-lua/t/024-access/multi-capture.t | 1 - .../modules/nginx-lua/t/024-access/on-abort.t | 1 - .../modules/nginx-lua/t/024-access/redirect.t | 1 - .../modules/nginx-lua/t/024-access/req-body.t | 1 - .../nginx-lua/t/024-access/request_body.t | 1 - .../modules/nginx-lua/t/024-access/sanity.t | 1 - .../modules/nginx-lua/t/024-access/satisfy.t | 1 - debian/modules/nginx-lua/t/024-access/sleep.t | 1 - .../nginx-lua/t/024-access/subrequest.t | 1 - .../nginx-lua/t/024-access/uthread-exec.t | 1 - .../nginx-lua/t/024-access/uthread-exit.t | 1 - .../nginx-lua/t/024-access/uthread-redirect.t | 1 - .../nginx-lua/t/024-access/uthread-spawn.t | 1 - debian/modules/nginx-lua/t/025-codecache.t | 1 - debian/modules/nginx-lua/t/026-mysql.t | 5 +- .../modules/nginx-lua/t/027-multi-capture.t | 1 - debian/modules/nginx-lua/t/029-http-time.t | 1 - debian/modules/nginx-lua/t/030-uri-args.t | 18 +- debian/modules/nginx-lua/t/031-post-args.t | 2 +- debian/modules/nginx-lua/t/032-iolist.t | 1 - debian/modules/nginx-lua/t/033-ctx.t | 1 - debian/modules/nginx-lua/t/034-match.t | 4 +- debian/modules/nginx-lua/t/035-gmatch.t | 5 +- debian/modules/nginx-lua/t/036-sub.t | 4 +- debian/modules/nginx-lua/t/037-gsub.t | 4 +- debian/modules/nginx-lua/t/038-match-o.t | 1 - debian/modules/nginx-lua/t/039-sub-o.t | 1 - debian/modules/nginx-lua/t/040-gsub-o.t | 1 - .../modules/nginx-lua/t/041-header-filter.t | 1 - debian/modules/nginx-lua/t/042-crc32.t | 1 - debian/modules/nginx-lua/t/045-ngx-var.t | 9 +- debian/modules/nginx-lua/t/046-hmac.t | 1 - debian/modules/nginx-lua/t/047-match-jit.t | 1 - debian/modules/nginx-lua/t/048-match-dfa.t | 1 - debian/modules/nginx-lua/t/049-gmatch-jit.t | 1 - debian/modules/nginx-lua/t/051-sub-jit.t | 1 - debian/modules/nginx-lua/t/053-gsub-jit.t | 1 - debian/modules/nginx-lua/t/055-subreq-vars.t | 1 - debian/modules/nginx-lua/t/056-flush.t | 1 - .../modules/nginx-lua/t/057-flush-timeout.t | 1 - debian/modules/nginx-lua/t/058-tcp-socket.t | 80 ++- .../modules/nginx-lua/t/060-lua-memcached.t | 1 - debian/modules/nginx-lua/t/061-lua-redis.t | 1 - debian/modules/nginx-lua/t/062-count.t | 2 +- debian/modules/nginx-lua/t/063-abort.t | 1 - debian/modules/nginx-lua/t/064-pcall.t | 1 - .../nginx-lua/t/065-tcp-socket-timeout.t | 41 +- .../nginx-lua/t/066-socket-receiveuntil.t | 1 - debian/modules/nginx-lua/t/067-req-socket.t | 1 - debian/modules/nginx-lua/t/069-null.t | 1 - debian/modules/nginx-lua/t/071-idle-socket.t | 1 - .../modules/nginx-lua/t/072-conditional-get.t | 1 - debian/modules/nginx-lua/t/073-backtrace.t | 1 - debian/modules/nginx-lua/t/074-prefix-var.t | 1 - debian/modules/nginx-lua/t/075-logby.t | 1 - debian/modules/nginx-lua/t/077-sleep.t | 99 ++- debian/modules/nginx-lua/t/078-hup-vars.t | 1 - .../nginx-lua/t/079-unused-directives.t | 1 - debian/modules/nginx-lua/t/080-hup-shdict.t | 1 - .../modules/nginx-lua/t/083-bad-sock-self.t | 1 - .../nginx-lua/t/084-inclusive-receiveuntil.t | 1 - debian/modules/nginx-lua/t/085-if.t | 1 - debian/modules/nginx-lua/t/086-init-by.t | 19 +- debian/modules/nginx-lua/t/087-udp-socket.t | 9 +- debian/modules/nginx-lua/t/088-req-method.t | 1 - debian/modules/nginx-lua/t/089-phase.t | 1 - .../nginx-lua/t/090-log-socket-errors.t | 19 +- debian/modules/nginx-lua/t/091-coroutine.t | 9 +- debian/modules/nginx-lua/t/092-eof.t | 1 - .../modules/nginx-lua/t/093-uthread-spawn.t | 1 - debian/modules/nginx-lua/t/094-uthread-exit.t | 1 - debian/modules/nginx-lua/t/095-uthread-exec.t | 1 - .../nginx-lua/t/096-uthread-redirect.t | 1 - .../modules/nginx-lua/t/097-uthread-rewrite.t | 1 - debian/modules/nginx-lua/t/098-uthread-wait.t | 1 - debian/modules/nginx-lua/t/100-client-abort.t | 1 - debian/modules/nginx-lua/t/101-on-abort.t | 1 - .../modules/nginx-lua/t/102-req-start-time.t | 1 - debian/modules/nginx-lua/t/103-req-http-ver.t | 1 - .../modules/nginx-lua/t/104-req-raw-header.t | 1 - debian/modules/nginx-lua/t/105-pressure.t | 1 - debian/modules/nginx-lua/t/106-timer.t | 1 - debian/modules/nginx-lua/t/107-timer-errors.t | 1 - debian/modules/nginx-lua/t/108-timer-safe.t | 1 - debian/modules/nginx-lua/t/109-timer-hup.t | 1 - debian/modules/nginx-lua/t/110-etag.t | 1 - .../modules/nginx-lua/t/111-req-header-ua.t | 1 - .../modules/nginx-lua/t/112-req-header-conn.t | 1 - .../nginx-lua/t/113-req-header-cookie.t | 1 - .../modules/nginx-lua/t/115-quote-sql-str.t | 1 - .../modules/nginx-lua/t/116-raw-req-socket.t | 1 - .../nginx-lua/t/117-raw-req-socket-timeout.t | 1 - .../modules/nginx-lua/t/119-config-prefix.t | 1 - debian/modules/nginx-lua/t/120-re-find.t | 30 +- debian/modules/nginx-lua/t/121-version.t | 1 - debian/modules/nginx-lua/t/122-worker.t | 1 - debian/modules/nginx-lua/t/123-lua-path.t | 1 - debian/modules/nginx-lua/t/124-init-worker.t | 2 +- .../modules/nginx-lua/t/125-configure-args.t | 1 - debian/modules/nginx-lua/t/126-shdict-frag.t | 1 - debian/modules/nginx-lua/t/127-uthread-kill.t | 3 +- .../nginx-lua/t/128-duplex-tcp-socket.t | 23 +- debian/modules/nginx-lua/t/129-ssl-socket.t | 573 +++++++++--------- debian/modules/nginx-lua/t/130-internal-api.t | 1 - debian/modules/nginx-lua/t/135-worker-id.t | 2 +- debian/modules/nginx-lua/t/137-req-misc.t | 1 - debian/modules/nginx-lua/t/138-balancer.t | 99 ++- debian/modules/nginx-lua/t/139-ssl-cert-by.t | 296 ++++++++- debian/modules/nginx-lua/t/140-ssl-c-api.t | 8 +- debian/modules/nginx-lua/t/141-luajit.t | 3 +- .../nginx-lua/t/142-ssl-session-store.t | 24 +- .../nginx-lua/t/143-ssl-session-fetch.t | 24 +- debian/modules/nginx-lua/t/146-malloc-trim.t | 41 +- .../nginx-lua/t/147-tcp-socket-timeouts.t | 2 +- .../nginx-lua/t/150-fake-delayed-load.t | 56 ++ debian/modules/nginx-lua/t/151-initby-hup.t | 168 +++++ debian/modules/nginx-lua/t/152-timer-every.t | 385 ++++++++++++ .../modules/nginx-lua/t/153-semaphore-hup.t | 154 +++++ debian/modules/nginx-lua/t/154-semaphore.t | 118 ++++ debian/modules/nginx-lua/t/cert/comodo-ca.crt | 29 + debian/modules/nginx-lua/t/cert/startcom.crt | 87 --- .../t/data/fake-delayed-load-module/config | 3 + .../ngx_http_lua_fake_delayed_load_module.c | 77 +++ .../t/data/fake-module/ngx_http_fake_module.c | 3 +- debian/modules/nginx-lua/util/build.sh | 1 + debian/modules/nginx-lua/util/gdbinit | 415 ------------- debian/modules/nginx-lua/util/reindex | 64 -- debian/modules/nginx-lua/valgrind.suppress | 15 + 203 files changed, 3745 insertions(+), 1536 deletions(-) create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c create mode 100644 debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h create mode 100644 debian/modules/nginx-lua/t/150-fake-delayed-load.t create mode 100644 debian/modules/nginx-lua/t/151-initby-hup.t create mode 100644 debian/modules/nginx-lua/t/152-timer-every.t create mode 100644 debian/modules/nginx-lua/t/153-semaphore-hup.t create mode 100644 debian/modules/nginx-lua/t/154-semaphore.t create mode 100644 debian/modules/nginx-lua/t/cert/comodo-ca.crt delete mode 100644 debian/modules/nginx-lua/t/cert/startcom.crt create mode 100644 debian/modules/nginx-lua/t/data/fake-delayed-load-module/config create mode 100644 debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c delete mode 100644 debian/modules/nginx-lua/util/gdbinit delete mode 100755 debian/modules/nginx-lua/util/reindex diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index ef2bb91..6b581cd 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -23,7 +23,7 @@ README for Modules versions nginx-lua Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.7 + Version: v0.10.10 Patch: openssl-1.1.0.patch Patch: build-nginx-1.11.11.patch Patch: discover-luajit-2.1.patch diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/nginx-lua/README.markdown index 3699a72..fac3a0d 100644 --- a/debian/modules/nginx-lua/README.markdown +++ b/debian/modules/nginx-lua/README.markdown @@ -62,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.7](https://github.com/openresty/lua-nginx-module/tags) released on 4 November 2016. +This document describes ngx_lua [v0.10.10](https://github.com/openresty/lua-nginx-module/tags) released on 8 August 2017. Synopsis ======== @@ -150,7 +150,7 @@ Synopsis } # use nginx var in code path - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; @@ -263,7 +263,7 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. Installation ============ -It is highly recommended to use the [OpenResty bundle](http://openresty.org) that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: `./configure --with-luajit && make && make install`. +It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -298,6 +298,12 @@ Build the source with this module: --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module + # Note that you may also want to add `./configure` options which are used in your + # current nginx build. + # You can get usually those options using command nginx -V + + # you can change the parallism number 2 below to fit the number of spare CPU cores in your + # machine. make -j2 make install ``` @@ -312,8 +318,9 @@ Starting from NGINX 1.9.11, you can also compile this module as a dynamic 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_lua_module.so; + + 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_lua_module.so; ``` [Back to TOC](#table-of-contents) @@ -406,14 +413,14 @@ Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible wi ```bash - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc ``` The `-bg` option can be used to include debug information in the LuaJIT bytecode file: ```bash - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc ``` Please refer to the official LuaJIT documentation on the `-b` option for more details: @@ -623,9 +630,9 @@ Known Issues TCP socket connect operation issues ----------------------------------- -The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. +The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. +However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. @@ -656,15 +663,29 @@ instead of the old deprecated form: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. -Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because +The use of Lua global variables is a generally inadvisable in the ngx_lua context as: -1. misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, -1. Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and -1. some Lua global variable references are just typos, which are hard to debug. +1. the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, +1. Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and +1. some Lua global variable references may include typing errors which make such difficult to debug. -It's *highly* recommended to always declare them via "local" in the scope that is reasonable. +It is therefore *highly* recommended to always declare such within an appropriate local scope instead. -To find out all the uses of Lua global variables in your Lua code, you can run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all your .lua source files: +```lua + + -- Avoid + foo = 123 + -- Recommended + local foo = 123 + + -- Avoid + function foo() return 123 end + -- Recommended + local function foo() return 123 end +``` + + +To find all instances of Lua global variables in your Lua code, run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all `.lua` source files: $ lua-releng Checking use of Lua global variables in file lib/foo/bar.lua ... @@ -709,28 +730,27 @@ will not work as expected. Cosockets Not Available Everywhere ---------------------------------- -Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). +Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). The cosockets are currently also disabled in the [init_by_lua*](#init_by_lua) and [init_worker_by_lua*](#init_worker_by_lua) directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. +There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. [Back to TOC](#table-of-contents) Special Escaping Sequences -------------------------- -**WARNING** We no longer suffer from this pitfall since the introduction of the -`*_by_lua_block {}` configuration directives. +**NOTE** Following the `v0.9.17` release, this pitfall can be avoided by using the `*_by_lua_block {}` configuration directives. -PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: +PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a `*_by_lua_block {}` directive. So the following snippet will not work as expected: ```nginx # nginx.conf ? location /test { ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG!! + ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE ? local m = ngx.re.match("hello, 1234", regex) ? if m then ngx.say(m[0]) else ngx.say("not matched!") end ? '; @@ -755,7 +775,7 @@ To avoid this, *double* escape the backslash: Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. +Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. ```nginx @@ -772,7 +792,7 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. -Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. +Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. The `[=[...]=]` form may be used as the default form if desired. ```nginx @@ -788,7 +808,7 @@ The `[=[...]=]` form may be used as the default form if desired. # evaluates to "1234" ``` -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. +An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. ```lua @@ -800,8 +820,8 @@ With this approach, the backslashes are only stripped by the Lua language parser -- evaluates to "1234" ``` -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - +Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. + ```lua -- test.lua @@ -811,6 +831,22 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str -- evaluates to "1234" ``` +As noted earlier, PCRE sequences presented within `*_by_lua_block {}` directives (available following the `v0.9.17` release) do not require modification. + +```nginx + + # nginx.conf + location /test { + content_by_lua_block { + local regex = "\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + } + } + # evaluates to "1234" +``` + + [Back to TOC](#table-of-contents) Mixing with SSI Not Supported @@ -871,7 +907,6 @@ servers in Lua. For example, * cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. * cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. * add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. -* review and apply Jader H. Silva's patch for `ngx.re.split()`. * review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option * use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. @@ -879,14 +914,14 @@ servers in Lua. For example, * add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -* cosocket: add client SSL certificiate support. +* cosocket: add client SSL certificate support. [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: +The changes made in every release of this module are listed in the change logs of the OpenResty bundle: @@ -955,9 +990,9 @@ Copyright and License This module is licensed under the BSD license. -Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -1001,6 +1036,7 @@ See Also Directives ========== +* [lua_capture_error_log](#lua_capture_error_log) * [lua_use_default_type](#lua_use_default_type) * [lua_malloc_trim](#lua_malloc_trim) * [lua_code_cache](#lua_code_cache) @@ -1074,6 +1110,56 @@ how the result will be used. Below is a diagram showing the order in which direc [Back to TOC](#table-of-contents) +lua_capture_error_log +--------------------- +**syntax:** *lua_capture_error_log size* + +**default:** *none* + +**context:** *http* + +Enables a buffer of the specified `size` for capturing all the nginx error log message data (not just those produced +by this module or the nginx http subsystem, but everything) without touching files or disks. + +You can use units like `k` and `m` in the `size` value, as in + +```nginx + + lua_capture_error_log 100k; +``` + +As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! + +This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. + +The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). + +You can read the messages in the buffer on the Lua land via the +[get_logs()](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs) +function of the +[ngx.errlog](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) +module of the [lua-resty-core](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) +library. This Lua API function will return the captured error log messages and +also remove these already read from the global capturing buffer, making room +for any new error log data. For this reason, the user should not configure this +buffer to be too big if the user read the buffered error log data fast enough. + +Note that the log level specified in the standard [error_log](http://nginx.org/r/error_log) directive +*does* have effect on this capturing facility. It only captures log +messages of a level no lower than the specified log level in the [error_log](http://nginx.org/r/error_log) directive. +The user can still choose to set an even higher filtering log level on the fly via the Lua API function +[errlog.set_filter_level](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level). +So it is more flexible than the static [error_log](http://nginx.org/r/error_log) directive. + +It is worth noting that there is no way to capture the debugging logs +without building OpenResty or NGINX with the `./configure` +option `--with-debug`. And enabling debugging logs is +strongly discouraged in production builds due to high overhead. + +This directive was first introduced in the `v0.10.9` release. + +[Back to TOC](#directives) + lua_use_default_type -------------------- **syntax:** *lua_use_default_type on | off* @@ -1082,7 +1168,7 @@ lua_use_default_type **context:** *http, server, location, location if* -Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. If you do not want a default `Content-Type` response header for your Lua request handlers, then turn this directive off. +Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. Deactivate this directive if a default `Content-Type` response header for Lua request handlers is not desired. This directive is turned on by default. @@ -1153,8 +1239,8 @@ The ngx_lua module does not support the `stat` mode available with the Apache `mod_lua` module (yet). Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. +discouraged for production use and should only be used during +development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. [Back to TOC](#directives) @@ -1176,6 +1262,8 @@ The default number of entries allowed is 1024 and when this limit is reached, ne 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... +If you are using the `ngx.re.*` implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the `resty.core.regex` module (or just the `resty.core` module), then an LRU cache is used for the regex cache being used here. + Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. [Back to TOC](#directives) @@ -1241,8 +1329,7 @@ init_by_lua **phase:** *loading-config* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [init_by_lua_block](#init_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_by_lua_block](#init_by_lua_block) directive instead. Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. @@ -1358,7 +1445,7 @@ init_worker_by_lua **phase:** *starting-worker* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). @@ -1384,8 +1471,8 @@ This hook is often used to create per-worker reoccurring timers (via the [ngx.ti end end - local ok, err = new_timer(delay, check) - if not ok then + local hdl, err = new_timer(delay, check) + if not hdl then log(ERR, "failed to create timer: ", err) return end @@ -1447,7 +1534,7 @@ set_by_lua **phase:** *rewrite* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; use the new [set_by_lua_block](#set_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [set_by_lua_block](#set_by_lua_block) directive instead. Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). @@ -1537,15 +1624,15 @@ set_by_lua_file **phase:** *rewrite* -Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. +Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. This directive requires the [ngx_devel_kit](https://github.com/simpl/ngx_devel_kit) module. @@ -1561,10 +1648,9 @@ content_by_lua **phase:** *content* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [content_by_lua_block](#content_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [content_by_lua_block](#content_by_lua_block) directive instead. -Acts as a "content handler" and executes Lua code string specified in `` for every request. +Acts as a "content handler" and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive should not be used in the same location. @@ -1613,16 +1699,16 @@ Nginx variables can be used in the `` string to provide When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. Nginx variables are supported in the file path for dynamic dispatch, for example: ```nginx - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; @@ -1643,8 +1729,7 @@ rewrite_by_lua **phase:** *rewrite tail* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1820,8 +1905,7 @@ access_by_lua **phase:** *access tail* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [access_by_lua_block](#access_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [access_by_lua_block](#access_by_lua_block) directive instead. Acts as an access phase handler and executes Lua code string specified in `` for every request. The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1933,7 +2017,7 @@ Nginx variables can be used in the `` string to provide When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. @@ -1950,8 +2034,7 @@ header_filter_by_lua **phase:** *output-header-filter* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. Uses Lua code specified in `` to define an output header filter. @@ -2029,8 +2112,7 @@ body_filter_by_lua **phase:** *output-body-filter* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. Uses Lua code specified in `` to define an output body filter. @@ -2166,15 +2248,14 @@ log_by_lua **phase:** *log* -**WARNING** Since the `v0.9.17` release, use of this directive is *discouraged*; -use the new [log_by_lua_block](#log_by_lua_block) directive instead. +**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [log_by_lua_block](#log_by_lua_block) directive instead. Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs before. Note that the following API functions are currently disabled within this context: * Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) +* Control API functions (e.g., [ngx.exit](#ngxexit)) * Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) * Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). @@ -2883,7 +2964,7 @@ lua_http10_buffering **context:** *http, server, location, location-if* -Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper `Content-Length` response header. +Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which relies on a proper `Content-Length` response header. If the Lua code explicitly sets a `Content-Length` response header before sending the headers (either explicitly via [ngx.send_headers](#ngxsend_headers) or implicitly via the first [ngx.say](#ngxsay) or [ngx.print](#ngxprint) call), then the HTTP 1.0 response buffering will be disabled even when this directive is turned on. @@ -2951,7 +3032,7 @@ lua_check_client_abort This directive controls whether to check for premature client connection abortion. -When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [ngx.on_abort](#ngxon_abort)) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. +When this directive is on, the ngx_lua module will monitor the premature connection close event on the downstream connections and when there is such an event, it will call the user Lua function callback (registered by [ngx.on_abort](#ngxon_abort)) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via [ngx.req.socket](#ngxreqsocket), then ngx_lua will neither stop all the running "light threads" nor call the user callback (if [ngx.on_abort](#ngxon_abort) has been called). Instead, the reading operation on [ngx.req.socket](#ngxreqsocket) will just return the error message "client aborted" as the second return value (the first return value is surely `nil`). @@ -3136,6 +3217,7 @@ Nginx API for Lua * [ngx.thread.kill](#ngxthreadkill) * [ngx.on_abort](#ngxon_abort) * [ngx.timer.at](#ngxtimerat) +* [ngx.timer.every](#ngxtimerevery) * [ngx.timer.running_count](#ngxtimerrunning_count) * [ngx.timer.pending_count](#ngxtimerpending_count) * [ngx.config.subsystem](#ngxconfigsubsystem) @@ -3280,7 +3362,7 @@ Setting `ngx.var.Foo` to a `nil` value will unset the `$Foo` Nginx variable. ngx.var.args = nil ``` -**WARNING** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, +**CAUTION** When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, ```lua @@ -3438,7 +3520,7 @@ ngx.ctx ------- **context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua** -This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). +This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). Consider the following example, @@ -3541,7 +3623,7 @@ When being used in the context of [init_worker_by_lua*](#init_worker_by_lua), th The `ngx.ctx` lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. -Because of the metamethod magic, never "local" the `ngx.ctx` table outside your Lua function scope on the Lua module level level due to [worker-level data sharing](#data-sharing-within-an-nginx-worker). For example, the following is bad: +Because of the metamethod magic, never "local" the `ngx.ctx` table outside your Lua function scope on the Lua module level due to [worker-level data sharing](#data-sharing-within-an-nginx-worker). For example, the following is bad: ```lua @@ -3549,7 +3631,7 @@ Because of the metamethod magic, never "local" the `ngx.ctx` table outside your local _M = {} -- the following line is bad since ngx.ctx is a per-request - -- data while this `ctx` variable is on the Lua module level + -- data while this ctx variable is on the Lua module level -- and thus is per-nginx-worker. local ctx = ngx.ctx @@ -3701,7 +3783,7 @@ The `args` option can also take plain query strings: This is functionally identical to the previous examples. -The `share_all_vars` option controls whether to share nginx variables among the current request and its subrequests. +The `share_all_vars` option controls whether to share nginx variables among the current request and its subrequests. If this option is set to `true`, then the current request and associated subrequests will share the same Nginx variable scope. Hence, changes to Nginx variables made by a subrequest will affect the current request. Care should be taken in using this option as variable scope sharing can have unexpected side effects. The `args`, `vars`, or `copy_all_vars` options are generally preferable instead. @@ -3768,7 +3850,7 @@ In addition to the two settings above, it is possible to specify values for variables in the subrequest using the `vars` option. These variables are set after the sharing or copying of variables has been evaluated, and provides a more efficient method of passing specific -values to a subrequest over encoding them as URL arguments and +values to a subrequest over encoding them as URL arguments and unescaping them in the Nginx config file. ```nginx @@ -3853,7 +3935,7 @@ Note that subrequests issued by [ngx.location.capture](#ngxlocationcapture) inhe request headers of the current request by default and that this may have unexpected side effects on the subrequest responses. For example, when using the standard `ngx_proxy` module to serve subrequests, an "Accept-Encoding: gzip" header in the main request may result -in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting +in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting [proxy_pass_request_headers](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass_request_headers) to `off` in subrequest locations. When the `body` option is not specified and the `always_forward_body` option is false (the default value), the `POST` and `PUT` subrequests will inherit the request bodies of the parent request (if any). @@ -3993,7 +4075,7 @@ will yield Set-Cookie: b=4; path=/ ``` -in the response headers. +in the response headers. Only Lua tables are accepted (Only the last element in the table will take effect for standard headers such as `Content-Type` that only accept a single value). @@ -4025,7 +4107,7 @@ The same applies to assigning an empty table: Setting `ngx.header.HEADER` after sending out response headers (either explicitly with [ngx.send_headers](#ngxsend_headers) or implicitly with [ngx.print](#ngxprint) and similar) will throw out a Lua exception. -Reading `ngx.header.HEADER` will return the value of the response header named `HEADER`. +Reading `ngx.header.HEADER` will return the value of the response header named `HEADER`. Underscores (`_`) in the header names will also be replaced by dashes (`-`) and the header names will be matched case-insensitively. If the response header is not present at all, `nil` will be returned. @@ -4536,7 +4618,7 @@ That is, they will take Lua boolean values `true`. However, they are different f Empty key arguments are discarded. `POST /test` with body `=hello&=world` will yield empty outputs for instance. -Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. However, the optional `max_args` function argument can be used to override this limit: @@ -4597,7 +4679,7 @@ the value of `ngx.req.get_headers()["Foo"]` will be a Lua (array) table such as: {"foo", "bar", "baz"} ``` -Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. However, the optional `max_headers` function argument can be used to override this limit: @@ -4999,6 +5081,7 @@ The optional `status` parameter specifies the HTTP status code to be used. The f * `301` * `302` (default) +* `303` * `307` It is `302` (`ngx.HTTP_MOVED_TEMPORARILY`) by default. @@ -5237,7 +5320,7 @@ Note that while this method accepts all [HTTP status constants](#http-status-con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the `return` statement, i.e., `return ngx.exit(...)` be used to reinforce the fact that the request processing is being terminated. -When being used in the contexts of [header_filter_by_lua](#header_filter_by_lua) and +When being used in the contexts of [header_filter_by_lua*](#header_filter_by_lua), [balancer_by_lua*](#balancer_by_lua_block), and [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block), `ngx.exit()` is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use `return` in combination as suggested above. @@ -5251,7 +5334,7 @@ ngx.eof Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". -When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on descent HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: +When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on well written HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: ```nginx @@ -5259,7 +5342,7 @@ When you disable the HTTP 1.1 keep-alive feature for your downstream connections keepalive_timeout 0; content_by_lua_block { ngx.say("got the task!") - ngx.eof() -- a descent HTTP client will close the connection at this point + ngx.eof() -- well written HTTP clients will close the connection at this point -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... } } @@ -5576,7 +5659,7 @@ ngx.time Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). -Updates of the Nginx time cache an be forced by calling [ngx.update_time](#ngxupdate_time) first. +Updates of the Nginx time cache can be forced by calling [ngx.update_time](#ngxupdate_time) first. [Back to TOC](#nginx-api-for-lua) @@ -5826,7 +5909,7 @@ The optional fourth argument, `ctx`, can be a Lua table holding an optional `pos local ctx = { pos = 2 } local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "34" + -- m[0] = "234" -- ctx.pos == 5 ``` @@ -6006,7 +6089,7 @@ When the `replace` is a string, then it is treated as a special template for str where `$0` referring to the whole substring matched by the pattern and `$1` referring to the first parenthesized capturing substring. -Curly braces can also be used to disambiguate variable names from the background string literals: +Curly braces can also be used to disambiguate variable names from the background string literals: ```lua @@ -6116,6 +6199,8 @@ The resulting object `dict` has the following methods: * [flush_expired](#ngxshareddictflush_expired) * [get_keys](#ngxshareddictget_keys) +All these methods are *atomic* operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same `lua_shared_dict` zone. + Here is an example: ```nginx @@ -6495,7 +6580,7 @@ Fetch a list of the keys from the dictionary, up to ``. By default, only the first 1024 keys (if any) are returned. When the `` argument is given the value `0`, then all the keys will be returned even there is more than 1024 keys in the dictionary. -**WARNING** Be careful when calling this method on dictionaries with a really huge number of keys. This method may lock the dictionary for quite a while and block all the nginx worker processes that are trying to access the dictionary. +**CAUTION** Avoid calling this method on dictionaries with a very large number of keys as it may lock the dictionary for significant amount of time and block Nginx worker processes trying to access the dictionary. This feature was first introduced in the `v0.7.3` release. @@ -7280,7 +7365,7 @@ Then it will generate the output 4 -"Light threads" are mostly useful for doing concurrent upstream requests in a single Nginx request handler, kinda like a generalized version of [ngx.location.capture_multi](#ngxlocationcapture_multi) that can work with all the [Nginx API for Lua](#nginx-api-for-lua). The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (very much like the Facebook BigPipe model): +"Light threads" are mostly useful for making concurrent upstream requests in a single Nginx request handler, much like a generalized version of [ngx.location.capture_multi](#ngxlocationcapture_multi) that can work with all the [Nginx API for Lua](#nginx-api-for-lua). The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (similar to Facebook's BigPipe model): ```lua @@ -7486,7 +7571,7 @@ See also [lua_check_client_abort](#lua_check_client_abort). ngx.timer.at ------------ -**syntax:** *ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* +**syntax:** *hdl, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)* **context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** @@ -7512,7 +7597,7 @@ Premature timer expiration happens when the Nginx worker process is trying to shut down, as in an Nginx configuration reload triggered by the `HUP` signal or in an Nginx server shutdown. When the Nginx worker is trying to shut down, one can no longer call `ngx.timer.at` to -create new timers with nonzero delays and in that case `ngx.timer.at` will return `nil` and +create new timers with nonzero delays and in that case `ngx.timer.at` will return a "conditional false" value and a string describing the error, that is, "process exiting". Starting from the `v0.9.3` release, it is allowed to create zero-delay timers even when the Nginx worker process starts shutting down. @@ -7571,6 +7656,9 @@ One can also create infinite re-occurring timers, for instance, a timer getting end ``` +It is recommended, however, to use the [ngx.timer.every](#ngxtimerevery) API function +instead for creating recurring timers since it is more robust. + Because timer callbacks run in the background and their running time will not add to any client request's response time, they can easily accumulate in the server and exhaust system resources due to either @@ -7610,6 +7698,25 @@ This API was first introduced in the `v0.8.0` release. [Back to TOC](#nginx-api-for-lua) +ngx.timer.every +--------------- +**syntax:** *hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)* + +**context:** *init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +Similar to the [ngx.timer.at](#ngxtimerat) API function, but + +1. `delay` *cannot* be zero, +1. timer will be created every `delay` seconds until the current Nginx worker process starts exiting. + +When success, returns a "conditional true" value (but not a `true`). Otherwise, returns a "conditional false" value and a string describing the error. + +This API also respect the [lua_max_pending_timers](#lua_max_pending_timers) and [lua_max_running_timers](#lua_max_running_timers). + +This API was first introduced in the `v0.10.9` release. + +[Back to TOC](#nginx-api-for-lua) + ngx.timer.running_count ----------------------- **syntax:** *count = ngx.timer.running_count()* diff --git a/debian/modules/nginx-lua/config b/debian/modules/nginx-lua/config index 01a6b3c..044deb9 100644 --- a/debian/modules/nginx-lua/config +++ b/debian/modules/nginx-lua/config @@ -360,6 +360,7 @@ HTTP_LUA_SRCS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \ $ngx_addon_dir/src/ngx_http_lua_ssl.c \ + $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \ " HTTP_LUA_DEPS=" \ @@ -420,6 +421,7 @@ HTTP_LUA_DEPS=" \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \ $ngx_addon_dir/src/ngx_http_lua_ssl.h \ + $ngx_addon_dir/src/ngx_http_lua_log_ringbuf.h \ " CFLAGS="$CFLAGS -DNDK_SET_VAR" @@ -472,33 +474,6 @@ ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);' . auto/feature -ngx_feature="mmap(sbrk(0))" -ngx_feature_libs= -ngx_feature_name="NGX_HTTP_LUA_HAVE_MMAP_SBRK" -ngx_feature_run=yes -ngx_feature_incs="#include -#include -#include -#include -#define align_ptr(p, a) \ - (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1)) -" -ngx_feature_test=" -#if defined(__x86_64__) -exit(mmap(align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0) < (void *) 0x40000000LL - ? 0 : 1); -#else -exit(1); -#endif -" -SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS" -CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS" - -. auto/feature - -CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS" - ngx_feature="__attribute__(constructor)" ngx_feature_libs= ngx_feature_name="NGX_HTTP_LUA_HAVE_CONSTRUCTOR" diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki index be454af..8393056 100644 --- a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/nginx-lua/doc/HttpLuaModule.wiki @@ -10,40 +10,40 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.7] released on 4 November 2016. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.10] released on 8 August 2017. = Synopsis = # set search paths for pure Lua external libraries (';;' is the default path): lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - + # set search paths for Lua external libraries written in C (can also use ';;'): lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - + server { location /lua_content { # MIME type determined by default_type: default_type 'text/plain'; - + content_by_lua_block { ngx.say('Hello,world!') } } - + location /nginx_var { # MIME type determined by default_type: default_type 'text/plain'; - + # try access /nginx_var?a=hello,world content_by_lua_block { ngx.say(ngx.var.arg_a) } } - + location = /request_body { client_max_body_size 50k; client_body_buffer_size 50k; - + content_by_lua_block { ngx.req.read_body() -- explicitly read the req body local data = ngx.req.get_body_data() @@ -62,13 +62,13 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t end } } - + # transparent non-blocking I/O in Lua via subrequests # (well, a better way is to use cosockets) location = /lua { # MIME type determined by default_type: default_type 'text/plain'; - + content_by_lua_block { local res = ngx.location.capture("/some_other_location") if res then @@ -78,51 +78,51 @@ This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/t end } } - + location = /foo { rewrite_by_lua_block { res = ngx.location.capture("/memc", { args = { cmd = "incr", key = ngx.var.uri } } ) } - + proxy_pass http://blah.blah.com; } - + location = /mixed { rewrite_by_lua_file /path/to/rewrite.lua; access_by_lua_file /path/to/access.lua; content_by_lua_file /path/to/content.lua; } - + # use nginx var in code path - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; content_by_lua_file /path/to/lua/app/root/$path.lua; } - + location / { client_max_body_size 100k; client_body_buffer_size 100k; - + access_by_lua_block { -- check the client IP address is in our black list if ngx.var.remote_addr == "132.5.72.3" then ngx.exit(ngx.HTTP_FORBIDDEN) end - + -- check if the URI contains bad words if ngx.var.uri and string.match(ngx.var.request_body, "evil") then return ngx.redirect("/terms_of_use.html") end - + -- tests passed } - + # proxy_pass/fastcgi_pass/etc settings } } @@ -197,7 +197,7 @@ Nginx cores older than 1.6.0 (exclusive) are *not* supported. = Installation = -It is highly recommended to use the [http://openresty.org OpenResty bundle] that bundles Nginx, ngx_lua, LuaJIT 2.0/2.1 (or the optional standard Lua 5.1 interpreter), as well as a package of powerful companion Nginx modules. The basic installation step is a simple command: ./configure --with-luajit && make && make install. +It is *highly* recommended to use [http://openresty.org OpenResty releases] which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. Alternatively, ngx_lua can be manually compiled into Nginx: @@ -220,31 +220,37 @@ Build the source with this module: # tell nginx's build system where to find LuaJIT 2.1: export LUAJIT_LIB=/path/to/luajit/lib export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - + # or tell where to find Lua if using Lua instead: #export LUA_LIB=/path/to/lua/lib #export LUA_INC=/path/to/lua/include - + # Here we assume Nginx is to be installed under /opt/nginx/. ./configure --prefix=/opt/nginx \ --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --add-module=/path/to/ngx_devel_kit \ --add-module=/path/to/lua-nginx-module - + + # Note that you may also want to add `./configure` options which are used in your + # current nginx build. + # You can get usually those options using command nginx -V + + # you can change the parallism number 2 below to fit the number of spare CPU cores in your + # machine. make -j2 make install == 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) +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_lua_module.so; -``` + == C Macro Configurations == @@ -309,13 +315,13 @@ As from the v0.5.0rc32 release, all *_by_lua_file conf Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc The -bg option can be used to include debug information in the LuaJIT bytecode file: - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.luac + /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc Please refer to the official LuaJIT documentation on the -b option for more details: @@ -451,7 +457,7 @@ Here is a complete small example: cat = 4, pig = 5, } - + function _M.get_age(name) return data[name] end @@ -495,9 +501,9 @@ If server-wide data sharing is required, then use one or more of the following a = Known Issues = == TCP socket connect operation issues == -The [[#tcpsock:connect|tcpsock:connect]] method may indicate success despite connection failures such as with Connection Refused errors. +The [[#tcpsock:connect|tcpsock:connect]] method may indicate success despite connection failures such as with Connection Refused errors. -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. +However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. @@ -520,15 +526,28 @@ instead of the old deprecated form: Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the require() built-in in the package.loaded table for later reference, and the module() builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the nil value. -Generally, use of Lua global variables is a really really bad idea in the context of ngx_lua because +The use of Lua global variables is a generally inadvisable in the ngx_lua context as: -# misuse of Lua globals has very bad side effects for concurrent requests when these variables are actually supposed to be local only, -# Lua global variables require Lua table look-up in the global environment (which is just a Lua table), which is kinda expensive, and -# some Lua global variable references are just typos, which are hard to debug. +# the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, +# Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and +# some Lua global variable references may include typing errors which make such difficult to debug. -It's *highly* recommended to always declare them via "local" in the scope that is reasonable. +It is therefore *highly* recommended to always declare such within an appropriate local scope instead. -To find out all the uses of Lua global variables in your Lua code, you can run the [https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all your .lua source files: + + -- Avoid + foo = 123 + -- Recommended + local foo = 123 + + -- Avoid + function foo() return 123 end + -- Recommended + local function foo() return 123 end + + + +To find all instances of Lua global variables in your Lua code, run the [https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng lua-releng tool] across all .lua source files: $ lua-releng Checking use of Lua global variables in file lib/foo/bar.lua ... @@ -565,24 +584,23 @@ will not work as expected. == Cosockets Not Available Everywhere == -Due the internal limitations in the nginx core, the cosocket API are disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. +Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [[#set_by_lua|set_by_lua*]], [[#log_by_lua|log_by_lua*]], [[#header_filter_by_lua|header_filter_by_lua*]], and [[#body_filter_by_lua|body_filter_by_lua]]. The cosockets are currently also disabled in the [[#init_by_lua|init_by_lua*]] and [[#init_worker_by_lua|init_worker_by_lua*]] directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a 0-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. +There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [[#ngx.timer.at|ngx.timer.at]] API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. == Special Escaping Sequences == -'''WARNING''' We no longer suffer from this pitfall since the introduction of the -*_by_lua_block {} configuration directives. +'''NOTE''' Following the v0.9.17 release, this pitfall can be avoided by using the *_by_lua_block {} configuration directives. -PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the Nginx config file parser before processing. So the following snippet will not work as expected: +PCRE sequences such as \d, \s, or \w, require special attention because in string literals, the backslash character, \, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a *_by_lua_block {} directive. So the following snippet will not work as expected: # nginx.conf ? location /test { ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG!! + ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE ? local m = ngx.re.match("hello, 1234", regex) ? if m then ngx.say(m[0]) else ngx.say("not matched!") end ? '; @@ -606,7 +624,7 @@ To avoid this, ''double'' escape the backslash: Here, \\\\d+ is stripped down to \\d+ by the Nginx config file parser and this is further stripped down to \d+ by the Lua language parser before running. -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", [[...]], in which case backslashes have to only be escaped once for the Nginx config file parser. +Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", [[...]], in which case backslashes have to only be escaped once for the Nginx config file parser. # nginx.conf @@ -622,7 +640,7 @@ Alternatively, the regex pattern can be presented as a long-bracketed Lua string Here, [[\\d+]] is stripped down to [[\d+]] by the Nginx config file parser and this is processed correctly. -Note that a longer from of the long bracket, [=[...]=], may be required if the regex pattern contains [...] sequences. +Note that a longer from of the long bracket, [=[...]=], may be required if the regex pattern contains [...] sequences. The [=[...]=] form may be used as the default form if desired. @@ -637,7 +655,7 @@ The [=[...]=] form may be used as the default form if desired. # evaluates to "1234" -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various *_by_lua_file directives. +An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various *_by_lua_file directives. With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. @@ -648,8 +666,8 @@ With this approach, the backslashes are only stripped by the Lua language parser -- evaluates to "1234" -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - +Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. + -- test.lua local regex = [[\d+]] @@ -658,6 +676,21 @@ Within external script files, PCRE sequences presented as long-bracketed Lua str -- evaluates to "1234" +As noted earlier, PCRE sequences presented within *_by_lua_block {} directives (available following the v0.9.17 release) do not require modification. + + + # nginx.conf + location /test { + content_by_lua_block { + local regex = "\d+" + local m = ngx.re.match("hello, 1234", regex) + if m then ngx.say(m[0]) else ngx.say("not matched!") end + } + } + # evaluates to "1234" + + + == Mixing with SSI Not Supported == Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. @@ -705,7 +738,6 @@ servers in Lua. For example, * cosocket: pool-based backend concurrency level control: implement automatic connect queueing when the backend concurrency exceeds its connection pool limit. * cosocket: review and merge aviramc's [https://github.com/openresty/lua-nginx-module/pull/290 patch] for adding the bsdrecv method. * add new API function ngx.resp.add_header to emulate the standard add_header config directive. -* review and apply Jader H. Silva's patch for ngx.re.split(). * review and apply vadim-pavlov's patch for [[#ngx.location.capture|ngx.location.capture]]'s extra_headers option * use ngx_hash_t to optimize the built-in header look-up process for [[#ngx.req.set_header|ngx.req.set_header]], [[#ngx.header.HEADER|ngx.header.HEADER]], and etc. * add configure options for different strategies of handling the cosocket connection exceeding in the pools. @@ -713,11 +745,11 @@ servers in Lua. For example, * add ignore_resp_headers, ignore_resp_body, and ignore_resp options to [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]] methods, to allow micro performance tuning on the user side. * add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. * add stat mode similar to [https://httpd.apache.org/docs/trunk/mod/mod_lua.html mod_lua]. -* cosocket: add client SSL certificiate support. +* cosocket: add client SSL certificate support. = Changes = -The changes of every release of this module can be obtained from the OpenResty bundle's change logs: +The changes made in every release of this module are listed in the change logs of the OpenResty bundle: http://openresty.org/#Changes @@ -772,7 +804,7 @@ To run specific test files: prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t -To run a specific test block in a particular test file, add the line --- ONLY to the test block you want to run, and then use the `prove` utility to run that .t file. +To run a specific test block in a particular test file, add the line --- ONLY to the test block you want to run, and then use the prove utility to run that .t file. There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [http://search.cpan.org/perldoc?Test::Nginx Test::Nginx documentation] for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: http://qa.openresty.org. @@ -780,9 +812,9 @@ There are also various testing modes based on mockeagain, valgrind, and etc. Ref This module is licensed under the BSD license. -Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) . +Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . -Copyright (C) 2009-2016, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (C) 2009-2017, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. All rights reserved. @@ -827,6 +859,52 @@ how the result will be used. Below is a diagram showing the order in which direc ![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) +== lua_capture_error_log == +'''syntax:''' ''lua_capture_error_log size'' + +'''default:''' ''none'' + +'''context:''' ''http'' + +Enables a buffer of the specified size for capturing all the nginx error log message data (not just those produced +by this module or the nginx http subsystem, but everything) without touching files or disks. + +You can use units like `k` and `m` in the size value, as in + + + lua_capture_error_log 100k; + + +As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! + +This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. + +The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). + +You can read the messages in the buffer on the Lua land via the +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs get_logs()] +function of the +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme ngx.errlog] +module of the [https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme lua-resty-core] +library. This Lua API function will return the captured error log messages and +also remove these already read from the global capturing buffer, making room +for any new error log data. For this reason, the user should not configure this +buffer to be too big if the user read the buffered error log data fast enough. + +Note that the log level specified in the standard [http://nginx.org/r/error_log error_log] directive +''does'' have effect on this capturing facility. It only captures log +messages of a level no lower than the specified log level in the [http://nginx.org/r/error_log error_log] directive. +The user can still choose to set an even higher filtering log level on the fly via the Lua API function +[https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level errlog.set_filter_level]. +So it is more flexible than the static [http://nginx.org/r/error_log error_log] directive. + +It is worth noting that there is no way to capture the debugging logs +without building OpenResty or NGINX with the ./configure +option --with-debug. And enabling debugging logs is +strongly discouraged in production builds due to high overhead. + +This directive was first introduced in the v0.10.9 release. + == lua_use_default_type == '''syntax:''' ''lua_use_default_type on | off'' @@ -834,7 +912,7 @@ how the result will be used. Below is a diagram showing the order in which direc '''context:''' ''http, server, location, location if'' -Specifies whether to use the MIME type specified by the [http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type default_type] directive for the default value of the Content-Type response header. If you do not want a default Content-Type response header for your Lua request handlers, then turn this directive off. +Specifies whether to use the MIME type specified by the [http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type default_type] directive for the default value of the Content-Type response header. Deactivate this directive if a default Content-Type response header for Lua request handlers is not desired. This directive is turned on by default. @@ -898,8 +976,8 @@ The ngx_lua module does not support the stat mode available with th Apache mod_lua module (yet). Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. +discouraged for production use and should only be used during +development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. == lua_regex_cache_max_entries == '''syntax:''' ''lua_regex_cache_max_entries '' @@ -918,6 +996,8 @@ The default number of entries allowed is 1024 and when this limit is reached, ne 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... +If you are using the ngx.re.* implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the resty.core.regex module (or just the resty.core module), then an LRU cache is used for the regex cache being used here. + Do not activate the o option for regular expressions (and/or replace string arguments for [[#ngx.re.sub|ngx.re.sub]] and [[#ngx.re.gsub|ngx.re.gsub]]) that are generated ''on the fly'' and give rise to infinite variations to avoid hitting the specified limit. == lua_regex_match_limit == @@ -971,8 +1051,7 @@ As from the v0.5.0rc29 release, the special notation $prefix< '''phase:''' ''loading-config'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#init_by_lua_block|init_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#init_by_lua_block|init_by_lua_block]] directive instead. Runs the Lua code specified by the argument on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. @@ -1041,7 +1120,7 @@ This directive was first introduced in the v0.5.5 release. Similar to the [[#init_by_lua|init_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1076,7 +1155,7 @@ This directive was first introduced in the v0.5.5 release. '''phase:''' ''starting-worker'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#init_worker_by_lua_block|init_worker_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#init_worker_by_lua_block|init_worker_by_lua_block]] directive instead. Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [[#init_by_lua|init_by_lua*]]. @@ -1101,8 +1180,8 @@ This hook is often used to create per-worker reoccurring timers (via the [[#ngx. end end - local ok, err = new_timer(delay, check) - if not ok then + local hdl, err = new_timer(delay, check) + if not hdl then log(ERR, "failed to create timer: ", err) return end @@ -1121,7 +1200,7 @@ This directive was first introduced in the v0.9.5 release. Similar to the [[#init_worker_by_lua|init_worker_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1154,7 +1233,7 @@ This directive was first introduced in the v0.9.5 release. '''phase:''' ''rewrite'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; use the new [[#set_by_lua_block|set_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#set_by_lua_block|set_by_lua_block]] directive instead. Executes code specified in with optional input arguments $arg1 $arg2 ..., and returns string output to $res. The code in can make [[#Nginx API for Lua|API calls]] and can retrieve input arguments from the ngx.arg table (index starts from 1 and increases sequentially). @@ -1177,15 +1256,15 @@ a time. However, a workaround is possible using the [[#ngx.var.VARIABLE|ngx.var. location /foo { set $diff ''; # we have to predefine the $diff variable here - + set_by_lua $sum ' local a = 32 local b = 56 - + ngx.var.diff = a - b; -- write to $diff directly return a + b; -- return the $sum value normally '; - + echo "sum = $sum, diff = $diff"; } @@ -1213,7 +1292,7 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki Similar to the [[#set_by_lua|set_by_lua]] directive except that # this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping), and # this directive does not support extra arguments after the Lua script as in [[#set_by_lua|set_by_lua]]. @@ -1235,15 +1314,15 @@ This directive was first introduced in the v0.9.17 release. '''phase:''' ''rewrite'' -Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. +Equivalent to [[#set_by_lua|set_by_lua]], except that the file specified by contains the Lua code, or, as from the v0.5.0rc32 release, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. Nginx variable interpolation is supported in the argument string of this directive. But special care must be taken for injection attacks. When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_kit] module. @@ -1256,10 +1335,9 @@ This directive requires the [https://github.com/simpl/ngx_devel_kit ngx_devel_ki '''phase:''' ''content'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#content_by_lua_block|content_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#content_by_lua_block|content_by_lua_block]] directive instead. -Acts as a "content handler" and executes Lua code string specified in for every request. +Acts as a "content handler" and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). Do not use this directive and other content handler directives in the same location. For example, this directive and the [[HttpProxyModule#proxy_pass|proxy_pass]] directive should not be used in the same location. @@ -1274,7 +1352,7 @@ Do not use this directive and other content handler directives in the same locat Similar to the [[#content_by_lua|content_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1301,15 +1379,15 @@ Nginx variables can be used in the string When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by +The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid reloading Nginx. Nginx variables are supported in the file path for dynamic dispatch, for example: - # WARNING: contents in nginx var must be carefully filtered, + # CAUTION: contents in nginx var must be carefully filtered, # otherwise there'll be great security risk! location ~ ^/app/([-_a-zA-Z0-9/]+) { set $path $1; @@ -1327,8 +1405,7 @@ But be very careful about malicious user inputs and always carefully validate or '''phase:''' ''rewrite tail'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#rewrite_by_lua_block|rewrite_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#rewrite_by_lua_block|rewrite_by_lua_block]] directive instead. Acts as a rewrite phase handler and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1376,7 +1453,7 @@ The right way of doing this is as follows: return ngx.redirect("/bar"); end '; - + echo "res = $b"; } @@ -1388,11 +1465,11 @@ Note that the [http://www.grid.net.ru/nginx/eval.en.html ngx_eval] module can be eval $res { proxy_pass http://foo.com/check-spam; } - + if ($res = 'spam') { rewrite ^ /terms-of-use.html redirect; } - + fastcgi_pass ...; } @@ -1404,7 +1481,7 @@ can be implemented in ngx_lua as: internal; proxy_pass http://foo.com/check-spam; } - + location / { rewrite_by_lua ' local res = ngx.location.capture("/check-spam") @@ -1412,7 +1489,7 @@ can be implemented in ngx_lua as: return ngx.redirect("/terms-of-use.html") end '; - + fastcgi_pass ...; } @@ -1447,7 +1524,7 @@ The rewrite_by_lua code will always run at the end of the rew Similar to the [[#rewrite_by_lua|rewrite_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1488,8 +1565,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [ '''phase:''' ''access tail'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#access_by_lua_block|access_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#access_by_lua_block|access_by_lua_block]] directive instead. Acts as an access phase handler and executes Lua code string specified in for every request. The Lua code may make [[#Nginx API for Lua|API calls]] and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). @@ -1502,12 +1578,12 @@ Note that this handler always runs ''after'' the standard [[HttpAccessModule]]. allow 192.168.1.0/24; allow 10.1.1.0/16; deny all; - + access_by_lua ' local res = ngx.location.capture("/mysql", { ... }) ... '; - + # proxy_pass/fastcgi_pass/... } @@ -1519,7 +1595,7 @@ Note that the [http://mdounin.ru/hg/ngx_http_auth_request_module/ ngx_auth_reque location / { auth_request /auth; - + # proxy_pass/fastcgi_pass/postgres_pass/... } @@ -1530,18 +1606,18 @@ can be implemented in ngx_lua as: location / { access_by_lua ' local res = ngx.location.capture("/auth") - + if res.status == ngx.HTTP_OK then return end - + if res.status == ngx.HTTP_FORBIDDEN then ngx.exit(res.status) end - + ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) '; - + # proxy_pass/fastcgi_pass/postgres_pass/... } @@ -1564,7 +1640,7 @@ of NGINX. Similar to the [[#access_by_lua|access_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1591,7 +1667,7 @@ Nginx variables can be used in the string When a relative path like foo/bar.lua is given, they will be turned into the absolute path relative to the server prefix path determined by the -p PATH command-line option while starting the Nginx server. -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached +When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [[#lua_code_cache|lua_code_cache]] off in nginx.conf to avoid repeatedly reloading Nginx. @@ -1605,8 +1681,7 @@ Nginx variables are supported in the file path for dynamic dispatch just as in [ '''phase:''' ''output-header-filter'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#header_filter_by_lua_block|header_filter_by_lua_block]] directive instead. Uses Lua code specified in to define an output header filter. @@ -1638,7 +1713,7 @@ This directive was first introduced in the v0.2.1rc20 release. Similar to the [[#header_filter_by_lua|header_filter_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1673,8 +1748,7 @@ This directive was first introduced in the v0.2.1rc20 release. '''phase:''' ''output-body-filter'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#body_filter_by_lua_block|body_filter_by_lua_block]] directive instead. Uses Lua code specified in to define an output body filter. @@ -1761,7 +1835,7 @@ This directive was first introduced in the v0.5.0rc32 release. Similar to the [[#body_filter_by_lua|body_filter_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -1796,15 +1870,14 @@ This directive was first introduced in the v0.5.0rc32 release. '''phase:''' ''log'' -'''WARNING''' Since the v0.9.17 release, use of this directive is ''discouraged''; -use the new [[#log_by_lua_block|log_by_lua_block]] directive instead. +'''NOTE''' Use of this directive is ''discouraged'' following the v0.9.17 release. Use the [[#log_by_lua_block|log_by_lua_block]] directive instead. Runs the Lua source code inlined as the at the log request processing phase. This does not replace the current access logs, but runs before. Note that the following API functions are currently disabled within this context: * Output API functions (e.g., [[#ngx.say|ngx.say]] and [[#ngx.send_headers|ngx.send_headers]]) -* Control API functions (e.g., [[#ngx.exit|ngx.exit]]) +* Control API functions (e.g., [[#ngx.exit|ngx.exit]]) * Subrequest API functions (e.g., [[#ngx.location.capture|ngx.location.capture]] and [[#ngx.location.capture_multi|ngx.location.capture_multi]]) * Cosocket API functions (e.g., [[#ngx.socket.tcp|ngx.socket.tcp]] and [[#ngx.req.socket|ngx.req.socket]]). @@ -1838,7 +1911,7 @@ Here is an example of gathering average data for [[HttpUpstreamModule#$upstream_ local log_dict = ngx.shared.log_dict local sum = log_dict:get("upstream_time-sum") local nb = log_dict:get("upstream_time-nb") - + if nb and sum then ngx.say("average upstream response time: ", sum / nb, " (", nb, " reqs)") @@ -1862,7 +1935,7 @@ This directive was first introduced in the v0.5.0rc31 release. Similar to the [[#log_by_lua|log_by_lua]] directive except that this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires +inside a pair of curly braces ({}) instead of in an NGINX string literal (which requires special character escaping). For instance, @@ -2430,7 +2503,7 @@ See also [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]]. '''context:''' ''http, server, location, location-if'' -Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which replies on a proper Content-Length response header. +Enables or disables automatic response buffering for HTTP 1.0 (or older) requests. This buffering mechanism is mainly used for HTTP 1.0 keep-alive which relies on a proper Content-Length response header. If the Lua code explicitly sets a Content-Length response header before sending the headers (either explicitly via [[#ngx.send_headers|ngx.send_headers]] or implicitly via the first [[#ngx.say|ngx.say]] or [[#ngx.print|ngx.print]] call), then the HTTP 1.0 response buffering will be disabled even when this directive is turned on. @@ -2486,7 +2559,7 @@ This directive was first introduced in the v0.5.0rc32 release. This directive controls whether to check for premature client connection abortion. -When this directive is turned on, the ngx_lua module will monitor the premature connection close event on the downstream connections. And when there is such an event, it will call the user Lua function callback (registered by [[#ngx.on_abort|ngx.on_abort]]) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. +When this directive is on, the ngx_lua module will monitor the premature connection close event on the downstream connections and when there is such an event, it will call the user Lua function callback (registered by [[#ngx.on_abort|ngx.on_abort]]) or just stop and clean up all the Lua "light threads" running in the current request's request handler when there is no user callback function registered. According to the current implementation, however, if the client closes the connection before the Lua code finishes reading the request body data via [[#ngx.req.socket|ngx.req.socket]], then ngx_lua will neither stop all the running "light threads" nor call the user callback (if [[#ngx.on_abort|ngx.on_abort]] has been called). Instead, the reading operation on [[#ngx.req.socket|ngx.req.socket]] will just return the error message "client aborted" as the second return value (the first return value is surely nil). @@ -2592,11 +2665,11 @@ Here is an example location /foo { set $a 32; set $b 56; - + set_by_lua $sum 'return tonumber(ngx.arg[1]) + tonumber(ngx.arg[2])' $a $b; - + echo $sum; } @@ -2646,7 +2719,7 @@ Setting ngx.var.Foo to a nil value will unset the -'''WARNING''' When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, +'''CAUTION''' When reading from an Nginx variable, Nginx will allocate memory in the per-request memory pool which is freed only at request termination. So when you need to read from an Nginx variable repeatedly in your Lua code, cache the Nginx variable value to your own Lua variable, for example, local val = ngx.var.some_var @@ -2655,7 +2728,7 @@ Setting ngx.var.Foo to a nil value will unset the nil while uninitialized (but defined) NGINX variables are evaluated to an empty Lua string. This API requires a relatively expensive metamethod call and it is recommended to avoid using it on hot code paths. @@ -2780,7 +2853,7 @@ There is a hard coded 2048 byte limitation on error message lengths == ngx.ctx == '''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*'' -This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). +This table can be used to store per-request Lua context data and has a life time identical to the current request (as with the Nginx variables). Consider the following example, @@ -2816,7 +2889,7 @@ Every request, including subrequests, has its own copy of the table. For example ngx.say("sub post: ", ngx.ctx.blah) } } - + location /main { content_by_lua_block { ngx.ctx.blah = 73 @@ -2847,7 +2920,7 @@ Internal redirection will destroy the original request ngx.ctx data ngx.say(ngx.ctx.foo) } } - + location /orig { content_by_lua_block { ngx.ctx.foo = "hello" @@ -2876,14 +2949,14 @@ When being used in the context of [[#init_worker_by_lua|init_worker_by_lua*]], t The ngx.ctx lookup requires relatively expensive metamethod calls and it is much slower than explicitly passing per-request data along by your own function arguments. So do not abuse this API for saving your own function arguments because it usually has quite some performance impact. -Because of the metamethod magic, never "local" the ngx.ctx table outside your Lua function scope on the Lua module level level due to [[#Data_Sharing_within_an_Nginx_Worker|worker-level data sharing]]. For example, the following is bad: +Because of the metamethod magic, never "local" the ngx.ctx table outside your Lua function scope on the Lua module level due to [[#Data_Sharing_within_an_Nginx_Worker|worker-level data sharing]]. For example, the following is bad: -- mymodule.lua local _M = {} -- the following line is bad since ngx.ctx is a per-request --- data while this `ctx` variable is on the Lua module level +-- data while this ctx variable is on the Lua module level -- and thus is per-nginx-worker. local ctx = ngx.ctx @@ -2907,7 +2980,7 @@ end return _M -That is, let the caller pass the `ctx` table explicitly via a function argument. +That is, let the caller pass the ctx table explicitly via a function argument. == ngx.location.capture == '''syntax:''' ''res = ngx.location.capture(uri, options?)'' @@ -3024,7 +3097,7 @@ The args option can also take plain query strings: This is functionally identical to the previous examples. -The share_all_vars option controls whether to share nginx variables among the current request and its subrequests. +The share_all_vars option controls whether to share nginx variables among the current request and its subrequests. If this option is set to true, then the current request and associated subrequests will share the same Nginx variable scope. Hence, changes to Nginx variables made by a subrequest will affect the current request. Care should be taken in using this option as variable scope sharing can have unexpected side effects. The args, vars, or copy_all_vars options are generally preferable instead. @@ -3089,7 +3162,7 @@ In addition to the two settings above, it is possible to specify values for variables in the subrequest using the vars option. These variables are set after the sharing or copying of variables has been evaluated, and provides a more efficient method of passing specific -values to a subrequest over encoding them as URL arguments and +values to a subrequest over encoding them as URL arguments and unescaping them in the Nginx config file. @@ -3171,7 +3244,7 @@ Note that subrequests issued by [[#ngx.location.capture|ngx.location.capture]] i request headers of the current request by default and that this may have unexpected side effects on the subrequest responses. For example, when using the standard ngx_proxy module to serve subrequests, an "Accept-Encoding: gzip" header in the main request may result -in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting +in gzipped responses that cannot be handled properly in Lua code. Original request headers should be ignored by setting [[HttpProxyModule#proxy_pass_request_headers|proxy_pass_request_headers]] to off in subrequest locations. When the body option is not specified and the always_forward_body option is false (the default value), the POST and PUT subrequests will inherit the request bodies of the parent request (if any). @@ -3201,11 +3274,11 @@ This function issues several parallel subrequests specified by the input table a { "/bar" }, { "/baz", { method = ngx.HTTP_POST, body = "hello" } }, } - + if res1.status == ngx.HTTP_OK then ... end - + if res2.body == "BLAH" then ... end @@ -3223,10 +3296,10 @@ Lua tables can be used for both requests and responses when the number of subreq table.insert(reqs, { "/postgres" }) table.insert(reqs, { "/redis" }) table.insert(reqs, { "/memcached" }) - + -- issue all the requests at once and wait until they all return local resps = { ngx.location.capture_multi(reqs) } - + -- loop over the responses table for i, resp in ipairs(resps) do -- process the response table "resp" @@ -3278,7 +3351,7 @@ The header names are matched case-insensitively. -- equivalent to ngx.header["Content-Type"] = 'text/plain' ngx.header.content_type = 'text/plain'; - + ngx.header["X-My-Header"] = 'blah blah'; @@ -3295,7 +3368,7 @@ will yield Set-Cookie: b=4; path=/ -in the response headers. +in the response headers. Only Lua tables are accepted (Only the last element in the table will take effect for standard headers such as Content-Type that only accept a single value). @@ -3323,7 +3396,7 @@ The same applies to assigning an empty table: Setting ngx.header.HEADER after sending out response headers (either explicitly with [[#ngx.send_headers|ngx.send_headers]] or implicitly with [[#ngx.print|ngx.print]] and similar) will throw out a Lua exception. -Reading ngx.header.HEADER will return the value of the response header named HEADER. +Reading ngx.header.HEADER will return the value of the response header named HEADER. Underscores (_) in the header names will also be replaced by dashes (-) and the header names will be matched case-insensitively. If the response header is not present at all, nil will be returned. @@ -3655,8 +3728,8 @@ Arguments without the = parts are treated as boolean argumen That is, they will take Lua boolean values true. However, they are different from arguments taking empty string values. GET /test?foo=&bar= will give something like - foo: - bar: + foo: + bar: Empty key arguments are discarded. GET /test?=hello&=world will yield an empty output for instance. @@ -3760,13 +3833,13 @@ Arguments without the = parts are treated as boolean argumen That is, they will take Lua boolean values true. However, they are different from arguments taking empty string values. POST /test with request body foo=&bar= will return something like - foo: - bar: + foo: + bar: Empty key arguments are discarded. POST /test with body =hello&=world will yield empty outputs for instance. -Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request arguments are parsed by default (including those with the same name) and that additional request arguments are silently discarded to guard against potential denial of service attacks. However, the optional max_args function argument can be used to override this limit: @@ -3818,7 +3891,7 @@ the value of ngx.req.get_headers()["Foo"] will be a Lua (array) tab {"foo", "bar", "baz"} -Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. +Note that a maximum of 100 request headers are parsed by default (including those with the same name) and that additional request headers are silently discarded to guard against potential denial of service attacks. However, the optional max_headers function argument can be used to override this limit: @@ -4164,6 +4237,7 @@ The optional status parameter specifies the HTTP status code to be * 301 * 302 (default) +* 303 * 307 It is 302 (ngx.HTTP_MOVED_TEMPORARILY) by default. @@ -4367,7 +4441,7 @@ Note that while this method accepts all [[#HTTP status constants|HTTP status con Also note that this method call terminates the processing of the current request and that it is recommended that a coding style that combines this method call with the return statement, i.e., return ngx.exit(...) be used to reinforce the fact that the request processing is being terminated. -When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua]] and +When being used in the contexts of [[#header_filter_by_lua|header_filter_by_lua*]], [[#balancer_by_lua_block|balancer_by_lua*]], and [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua*]], ngx.exit() is an asynchronous operation and will return immediately. This behavior may change in future and it is recommended that users always use return in combination as suggested above. @@ -4378,14 +4452,14 @@ an asynchronous operation and will return immediately. This behavior may change Explicitly specify the end of the response output stream. In the case of HTTP 1.1 chunked encoded output, it will just trigger the Nginx core to send out the "last chunk". -When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on descent HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: +When you disable the HTTP 1.1 keep-alive feature for your downstream connections, you can rely on well written HTTP clients to close the connection actively for you when you call this method. This trick can be used do back-ground jobs without letting the HTTP clients to wait on the connection, as in the following example: location = /async { keepalive_timeout 0; content_by_lua_block { ngx.say("got the task!") - ngx.eof() -- a descent HTTP client will close the connection at this point + ngx.eof() -- well written HTTP clients will close the connection at this point -- access MySQL, PostgreSQL, Redis, Memcached, and etc here... } } @@ -4646,7 +4720,7 @@ This is the local time. Returns the elapsed seconds from the epoch for the current time stamp from the nginx cached time (no syscall involved unlike Lua's date library). -Updates of the Nginx time cache an be forced by calling [[#ngx.update_time|ngx.update_time]] first. +Updates of the Nginx time cache can be forced by calling [[#ngx.update_time|ngx.update_time]] first. == ngx.now == '''syntax:''' ''secs = ngx.now()'' @@ -4858,7 +4932,7 @@ The optional fourth argument, ctx, can be a Lua table holding an op local ctx = { pos = 2 } local m, err = ngx.re.match("1234, hello", "[0-9]+", "", ctx) - -- m[0] = "34" + -- m[0] = "234" -- ctx.pos == 5 @@ -5024,7 +5098,7 @@ When the replace is a string, then it is treated as a special templ where $0 referring to the whole substring matched by the pattern and $1 referring to the first parenthesized capturing substring. -Curly braces can also be used to disambiguate variable names from the background string literals: +Curly braces can also be used to disambiguate variable names from the background string literals: local newstr, n, err = ngx.re.sub("hello, 1234", "[0-9]", "${0}00") @@ -5123,6 +5197,8 @@ The resulting object dict has the following methods: * [[#ngx.shared.DICT.flush_expired|flush_expired]] * [[#ngx.shared.DICT.get_keys|get_keys]] +All these methods are ''atomic'' operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same lua_shared_dict zone. + Here is an example: @@ -5343,7 +5419,7 @@ The value argument and init argument can be any valid This method was first introduced in the v0.3.1rc22 release. -The optional `init` parameter was first added in the v0.10.6 release. +The optional init parameter was first added in the v0.10.6 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. @@ -5445,7 +5521,7 @@ Fetch a list of the keys from the dictionary, up to . By default, only the first 1024 keys (if any) are returned. When the argument is given the value 0, then all the keys will be returned even there is more than 1024 keys in the dictionary. -'''WARNING''' Be careful when calling this method on dictionaries with a really huge number of keys. This method may lock the dictionary for quite a while and block all the nginx worker processes that are trying to access the dictionary. +'''CAUTION''' Avoid calling this method on dictionaries with a very large number of keys as it may lock the dictionary for significant amount of time and block Nginx worker processes trying to access the dictionary. This feature was first introduced in the v0.7.3 release. @@ -5724,7 +5800,7 @@ session userdata returned by a previous sslhandshake call for exactly the same target. For short-lived connections, reusing SSL sessions can usually speed up the handshake by one order by magnitude but it is not so useful if the connection pool is enabled. This argument defaults to -`nil`. If this argument takes the boolean `false` value, no SSL session +nil. If this argument takes the boolean false value, no SSL session userdata would return by this call and only a Lua boolean will be returned as the first return value; otherwise the current SSL session will always be returned as the first argument in case of successes. @@ -5737,7 +5813,7 @@ also used to validate the server name specified in the server certificate sent f the remote. The optional ssl_verify argument takes a Lua boolean value to -control whether to perform SSL verification. When set to `true`, the server +control whether to perform SSL verification. When set to true, the server certificate will be verified according to the CA certificates specified by the [[#lua_ssl_trusted_certificate|lua_ssl_trusted_certificate]] directive. You may also need to adjust the [[#lua_ssl_verify_depth|lua_ssl_verify_depth]] @@ -6148,7 +6224,7 @@ Then it will generate the output 4 -"Light threads" are mostly useful for doing concurrent upstream requests in a single Nginx request handler, kinda like a generalized version of [[#ngx.location.capture_multi|ngx.location.capture_multi]] that can work with all the [[#Nginx API for Lua|Nginx API for Lua]]. The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (very much like the Facebook BigPipe model): +"Light threads" are mostly useful for making concurrent upstream requests in a single Nginx request handler, much like a generalized version of [[#ngx.location.capture_multi|ngx.location.capture_multi]] that can work with all the [[#Nginx API for Lua|Nginx API for Lua]]. The following example demonstrates parallel requests to MySQL, Memcached, and upstream HTTP services in a single Lua handler, and outputting the results in the order that they actually return (similar to Facebook's BigPipe model): -- query mysql, memcached, and a remote http service at the same time, @@ -6187,7 +6263,7 @@ Then it will generate the output ngx.thread.spawn(query_mysql) -- create thread 1 ngx.thread.spawn(query_memcached) -- create thread 2 - ngx.thread.spawn(query_http) -- create thread 3 + ngx.thread.spawn(query_http) -- create thread 3 This API was first enabled in the v0.7.0 release. @@ -6338,7 +6414,7 @@ This API was first introduced in the v0.7.4 release. See also [[#lua_check_client_abort|lua_check_client_abort]]. == ngx.timer.at == -'''syntax:''' ''ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' +'''syntax:''' ''hdl, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)'' '''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' @@ -6364,7 +6440,7 @@ Premature timer expiration happens when the Nginx worker process is trying to shut down, as in an Nginx configuration reload triggered by the HUP signal or in an Nginx server shutdown. When the Nginx worker is trying to shut down, one can no longer call ngx.timer.at to -create new timers with nonzero delays and in that case ngx.timer.at will return nil and +create new timers with nonzero delays and in that case ngx.timer.at will return a "conditional false" value and a string describing the error, that is, "process exiting". Starting from the v0.9.3 release, it is allowed to create zero-delay timers even when the Nginx worker process starts shutting down. @@ -6413,7 +6489,7 @@ One can also create infinite re-occurring timers, for instance, a timer getting return end end - + local ok, err = ngx.timer.at(delay, handler) if not ok then ngx.log(ngx.ERR, "failed to create the timer: ", err) @@ -6421,6 +6497,9 @@ One can also create infinite re-occurring timers, for instance, a timer getting end +It is recommended, however, to use the [[#ngx.timer.every|ngx.timer.every]] API function +instead for creating recurring timers since it is more robust. + Because timer callbacks run in the background and their running time will not add to any client request's response time, they can easily accumulate in the server and exhaust system resources due to either @@ -6458,6 +6537,22 @@ You can pass most of the standard Lua values (nils, booleans, numbers, strings, This API was first introduced in the v0.8.0 release. +== ngx.timer.every == +'''syntax:''' ''hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)'' + +'''context:''' ''init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +Similar to the [[#ngx.timer.at|ngx.timer.at]] API function, but + +# delay ''cannot'' be zero, +# timer will be created every delay seconds until the current Nginx worker process starts exiting. + +When success, returns a "conditional true" value (but not a true). Otherwise, returns a "conditional false" value and a string describing the error. + +This API also respect the [[#lua_max_pending_timers|lua_max_pending_timers]] and [[#lua_max_running_timers|lua_max_running_timers]]. + +This API was first introduced in the v0.10.9 release. + == ngx.timer.running_count == '''syntax:''' ''count = ngx.timer.running_count()'' @@ -6481,8 +6576,8 @@ This directive was first introduced in the v0.9.20 release. '''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, init_by_lua*, init_worker_by_lua*'' -This string field indicates the current NGINX subsystem the current Lua environment is based on. For this module, this field always takes the string value `"http"`. For -[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value `"stream"`. +This string field indicates the current NGINX subsystem the current Lua environment is based on. For this module, this field always takes the string value "http". For +[https://github.com/openresty/stream-lua-nginx-module#readme ngx_stream_lua_module], however, this field takes the value "stream". This field was first introduced in the 0.10.1. @@ -6563,7 +6658,7 @@ This API was first introduced in the 0.9.5 release. Returns the total number of the Nginx worker processes (i.e., the value configured by the [http://nginx.org/en/docs/ngx_core_module.html#worker_processes worker_processes] -directive in `nginx.conf`). +directive in nginx.conf). This API was first introduced in the 0.9.20 release. @@ -6575,11 +6670,11 @@ This API was first introduced in the 0.9.20 release. Returns the ordinal number of the current Nginx worker processes (starting from number 0). -So if the total number of workers is `N`, then this method may return a number between 0 -and `N - 1` (inclusive). +So if the total number of workers is N, then this method may return a number between 0 +and N - 1 (inclusive). This function returns meaningful values only for NGINX 1.9.1+. With earlier versions of NGINX, it -always returns `nil`. +always returns nil. See also [[#ngx.worker.count|ngx.worker.count]]. diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h index 3737149..cd64fc8 100644 --- a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10007 +#define ngx_http_lua_version 10010 typedef struct { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_api.c b/debian/modules/nginx-lua/src/ngx_http_lua_api.c index b72c707..7b590e7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_api.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_api.c @@ -56,11 +56,10 @@ ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, lua_pushcfunction(L, func); lua_setfield(L, -2, package); lua_pop(L, 2); - - return NGX_OK; } - /* L == NULL */ + /* we always register preload_hooks since we always create new Lua VMs + * when lua code cache is off. */ if (lmcf->preload_hooks == NULL) { lmcf->preload_hooks = @@ -176,7 +175,9 @@ ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data) } zone->shm = shm_zone->shm; +#if defined(nginx_version) && nginx_version >= 1009000 zone->noreuse = shm_zone->noreuse; +#endif if (zone->init(zone, odata) != NGX_OK) { return NGX_ERROR; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.c b/debian/modules/nginx-lua/src/ngx_http_lua_args.c index 0c307d6..b43697c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_args.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_args.c @@ -184,7 +184,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) if (r->request_body->temp_file) { lua_pushnil(L); - lua_pushliteral(L, "requesty body in temp file not supported"); + lua_pushliteral(L, "request body in temp file not supported"); return 2; } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c index 0adf787..2fa634e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c @@ -314,7 +314,13 @@ ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data) if (ctx->exited && ctx->exit_code != NGX_OK) { rc = ctx->exit_code; - if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { + if (rc == NGX_ERROR + || rc == NGX_BUSY + || rc == NGX_DECLINED +#ifdef HAVE_BALANCER_STATUS_CODE_PATCH + || rc >= NGX_HTTP_SPECIAL_RESPONSE +#endif + ) { return rc; } @@ -640,7 +646,7 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, int count, char **err) { #if (nginx_version >= 1007005) - ngx_uint_t max_tries; + ngx_uint_t max_tries, total; #endif ngx_http_lua_ctx_t *ctx; ngx_http_upstream_t *u; @@ -681,9 +687,10 @@ ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, #if (nginx_version >= 1007005) max_tries = r->upstream->conf->next_upstream_tries; + total = bp->total_tries + r->upstream->peer.tries - 1; - if (bp->total_tries + count > max_tries) { - count = max_tries - bp->total_tries; + if (max_tries && total + count > max_tries) { + count = max_tries - total; *err = "reduced tries due to limit"; } else { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/nginx-lua/src/ngx_http_lua_common.h index 267952b..e389783 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_common.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_common.h @@ -22,6 +22,19 @@ #include +#if (NGX_PCRE) + +#include + +#if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) +# define LUA_HAVE_PCRE_JIT 1 +#else +# define LUA_HAVE_PCRE_JIT 0 +#endif + +#endif + + #if !defined(nginx_version) || (nginx_version < 1006000) #error at least nginx 1.6.0 is required but found an older version #endif @@ -138,7 +151,7 @@ typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t; typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, lua_State *L); typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r, - ngx_http_lua_srv_conf_t *lmcf, lua_State *L); + ngx_http_lua_srv_conf_t *lscf, lua_State *L); typedef struct { @@ -168,6 +181,11 @@ struct ngx_http_lua_main_conf_s { ngx_int_t regex_cache_entries; ngx_int_t regex_cache_max_entries; ngx_int_t regex_match_limit; + +#if (LUA_HAVE_PCRE_JIT) + pcre_jit_stack *jit_stack; +#endif + #endif ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */ @@ -199,6 +217,12 @@ struct ngx_http_lua_main_conf_s { of reqeusts */ ngx_uint_t malloc_trim_req_count; +#if nginx_version >= 1011011 + /* the following 2 fields are only used by ngx.req.raw_headers() for now */ + ngx_buf_t **busy_buf_ptrs; + ngx_int_t busy_buf_ptr_count; +#endif + unsigned requires_header_filter:1; unsigned requires_body_filter:1; unsigned requires_capture_filter:1; @@ -206,6 +230,7 @@ struct ngx_http_lua_main_conf_s { unsigned requires_access:1; unsigned requires_log:1; unsigned requires_shm:1; + unsigned requires_capture_log:1; }; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/nginx-lua/src/ngx_http_lua_control.c index 249d763..ae36505 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_control.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_control.c @@ -212,10 +212,12 @@ ngx_http_lua_ngx_redirect(lua_State *L) if (rc != NGX_HTTP_MOVED_TEMPORARILY && rc != NGX_HTTP_MOVED_PERMANENTLY + && rc != NGX_HTTP_SEE_OTHER && rc != NGX_HTTP_TEMPORARY_REDIRECT) { return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY, " - "ngx.HTTP_MOVED_PERMANENTLY, and " + "ngx.HTTP_MOVED_PERMANENTLY, " + "ngx.HTTP_SEE_OTHER, and " "ngx.HTTP_TEMPORARY_REDIRECT are allowed"); } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c index 862edda..6a562f4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.c @@ -27,6 +27,8 @@ #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_lex.h" #include "api/ngx_http_lua_api.h" +#include "ngx_http_lua_log_ringbuf.h" +#include "ngx_http_lua_log.h" typedef struct ngx_http_lua_block_parser_ctx_s @@ -1700,6 +1702,71 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, } +char * +ngx_http_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ +#ifndef HAVE_INTERCEPT_ERROR_LOG_PATCH + return "not found: missing the capture error log patch for nginx"; +#else + ngx_str_t *value; + ssize_t size; + u_char *data; + ngx_cycle_t *cycle; + ngx_http_lua_main_conf_t *lmcf = conf; + ngx_http_lua_log_ringbuf_t *ringbuf; + + value = cf->args->elts; + cycle = cf->cycle; + + if (lmcf->requires_capture_log) { + return "is duplicate"; + } + + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid capture error log size \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + size = ngx_parse_size(&value[1]); + + if (size < NGX_MAX_ERROR_STR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid capture error log size \"%V\", " + "minimum size is %d", &value[1], + NGX_MAX_ERROR_STR); + return NGX_CONF_ERROR; + } + + if (cycle->intercept_error_log_handler) { + return "capture error log handler has been hooked"; + } + + ringbuf = (ngx_http_lua_log_ringbuf_t *) + ngx_palloc(cf->pool, sizeof(ngx_http_lua_log_ringbuf_t)); + if (ringbuf == NULL) { + return NGX_CONF_ERROR; + } + + data = ngx_palloc(cf->pool, size); + if (data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_http_lua_log_ringbuf_init(ringbuf, data, size); + + lmcf->requires_capture_log = 1; + cycle->intercept_error_log_handler = (ngx_log_intercept_pt) + ngx_http_lua_capture_log_handler; + cycle->intercept_error_log_data = ringbuf; + + return NGX_CONF_OK; +#endif +} + + /* * ngx_http_lua_strlstrn() is intended to search for static substring * with known length in string until the argument last. The argument n diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h index be591f3..5abfe4d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_directive.h @@ -67,9 +67,10 @@ ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, char *ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf, ngx_command_t *cmd); +char *ngx_http_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); #endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c index 0af56f6..6700ce8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.c @@ -26,6 +26,9 @@ static int ngx_http_lua_ngx_req_get_headers(lua_State *L); static int ngx_http_lua_ngx_req_header_clear(lua_State *L); static int ngx_http_lua_ngx_req_header_set(lua_State *L); static int ngx_http_lua_ngx_resp_get_headers(lua_State *L); +#if nginx_version >= 1011011 +void ngx_http_lua_ngx_raw_header_cleanup(void *data); +#endif static int @@ -77,6 +80,11 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) size_t size; ngx_buf_t *b, *first = NULL; ngx_int_t i, j; +#if nginx_version >= 1011011 + ngx_buf_t **bb; + ngx_chain_t *cl; + ngx_http_lua_main_conf_t *lmcf; +#endif ngx_connection_t *c; ngx_http_request_t *r, *mr; ngx_http_connection_t *hc; @@ -93,6 +101,10 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) return luaL_error(L, "no request object found"); } +#if nginx_version >= 1011011 + lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); +#endif + ngx_http_lua_check_fake_request(L, r); mr = r->main; @@ -109,8 +121,13 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("hc->nbusy: %d", (int) hc->nbusy); if (hc->nbusy) { +#if nginx_version >= 1011011 + dd("hc->busy: %p %p %p %p", hc->busy->buf->start, hc->busy->buf->pos, + hc->busy->buf->last, hc->busy->buf->end); +#else dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos, hc->busy[0]->last, hc->busy[0]->end); +#endif } dd("request line: %p %p", mr->request_line.data, @@ -146,9 +163,37 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) dd("size: %d", (int) size); if (hc->nbusy) { +#if nginx_version >= 1011011 + if (hc->nbusy > lmcf->busy_buf_ptr_count) { + if (lmcf->busy_buf_ptrs) { + ngx_free(lmcf->busy_buf_ptrs); + } + + lmcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), + r->connection->log); + + if (lmcf->busy_buf_ptrs == NULL) { + return luaL_error(L, "no memory"); + } + + lmcf->busy_buf_ptr_count = hc->nbusy; + } + + bb = lmcf->busy_buf_ptrs; + for (cl = hc->busy; cl; cl = cl->next) { + *bb++ = cl->buf; + } +#endif b = NULL; + +#if nginx_version >= 1011011 + bb = lmcf->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 dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start), b->start); @@ -223,8 +268,15 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) } if (hc->nbusy) { + +#if nginx_version >= 1011011 + bb = lmcf->busy_buf_ptrs; + for (i = hc->nbusy - 1; i >= 0; i--) { + b = bb[i]; +#else for (i = 0; i < hc->nbusy; i++) { b = hc->busy[i]; +#endif if (!found) { if (b != first) { @@ -444,6 +496,8 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_request_t *r; + ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; u_char *lowcase_key = NULL; size_t lowcase_key_sz = 0; ngx_uint_t i; @@ -475,6 +529,22 @@ ngx_http_lua_ngx_resp_get_headers(lua_State *L) return luaL_error(L, "no request object found"); } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + ngx_http_lua_check_fake_request(L, r); part = &r->headers_out.headers.part; @@ -603,12 +673,19 @@ ngx_http_lua_ngx_header_get(lua_State *L) ngx_uint_t i; size_t len; ngx_http_lua_loc_conf_t *llcf; + ngx_http_lua_ctx_t *ctx; + ngx_int_t rc; r = ngx_http_lua_get_req(L); if (r == NULL) { return luaL_error(L, "no request object found"); } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + return luaL_error(L, "no ctx found"); + } + ngx_http_lua_check_fake_request(L, r); /* we skip the first argument that is the table */ @@ -640,6 +717,17 @@ ngx_http_lua_ngx_header_get(lua_State *L) key.len = len; + if (!ctx->headers_set) { + rc = ngx_http_lua_set_content_type(r); + if (rc != NGX_OK) { + return luaL_error(L, + "failed to set default content type: %d", + (int) rc); + } + + ctx->headers_set = 1; + } + return ngx_http_lua_get_output_header(L, r, &key); } @@ -718,7 +806,7 @@ ngx_http_lua_ngx_header_set(lua_State *L) ngx_str_null(&value); } else if (lua_type(L, 3) == LUA_TTABLE) { - n = luaL_getn(L, 3); + n = lua_objlen(L, 3); if (n == 0) { ngx_str_null(&value); @@ -852,7 +940,7 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L) ngx_str_null(&value); } else if (lua_type(L, 2) == LUA_TTABLE) { - n = luaL_getn(L, 2); + n = lua_objlen(L, 2); if (n == 0) { ngx_str_null(&value); @@ -1262,6 +1350,7 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, ngx_uint_t i; ngx_table_elt_t *h; ngx_list_part_t *part; + ngx_http_lua_ctx_t *ctx; ngx_http_lua_loc_conf_t *llcf; @@ -1269,6 +1358,21 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, return NGX_HTTP_LUA_FFI_BAD_CONTEXT; } + ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); + if (ctx == NULL) { + /* *errmsg = "no ctx found"; */ + return NGX_ERROR; + } + + if (!ctx->headers_set) { + if (ngx_http_lua_set_content_type(r) != NGX_OK) { + /* *errmsg = "failed to set default content type"; */ + return NGX_ERROR; + } + + ctx->headers_set = 1; + } + llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); if (llcf->transform_underscores_in_resp_headers && memchr(key, '_', key_len) != NULL) @@ -1379,4 +1483,20 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, #endif /* NGX_LUA_NO_FFI_API */ +#if nginx_version >= 1011011 +void +ngx_http_lua_ngx_raw_header_cleanup(void *data) +{ + ngx_http_lua_main_conf_t *lmcf; + + lmcf = (ngx_http_lua_main_conf_t *) data; + + if (lmcf->busy_buf_ptrs) { + ngx_free(lmcf->busy_buf_ptrs); + lmcf->busy_buf_ptrs = NULL; + } +} +#endif + + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.h b/debian/modules/nginx-lua/src/ngx_http_lua_headers.h index 39f1114..ee4d21c 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_headers.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_headers.h @@ -15,6 +15,9 @@ void ngx_http_lua_inject_resp_header_api(lua_State *L); void ngx_http_lua_inject_req_header_api(lua_State *L); void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L); +#if nginx_version >= 1011011 +void ngx_http_lua_ngx_raw_header_cleanup(void *data); +#endif #endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.c b/debian/modules/nginx-lua/src/ngx_http_lua_log.c index c2b2269..c18e6b0 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_log.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log.c @@ -13,6 +13,7 @@ #include "ngx_http_lua_log.h" #include "ngx_http_lua_util.h" +#include "ngx_http_lua_log_ringbuf.h" static int ngx_http_lua_print(lua_State *L); @@ -313,4 +314,120 @@ ngx_http_lua_inject_log_consts(lua_State *L) /* }}} */ } + +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH +ngx_int_t +ngx_http_lua_capture_log_handler(ngx_log_t *log, + ngx_uint_t level, u_char *buf, size_t n) +{ + ngx_http_lua_log_ringbuf_t *ringbuf; + + dd("enter"); + + ringbuf = (ngx_http_lua_log_ringbuf_t *) + ngx_cycle->intercept_error_log_data; + + if (level > ringbuf->filter_level) { + return NGX_OK; + } + + ngx_http_lua_log_ringbuf_write(ringbuf, level, buf, n); + + dd("capture log: %s\n", buf); + + return NGX_OK; +} +#endif + + +#ifndef NGX_LUA_NO_FFI_API +int +ngx_http_lua_ffi_errlog_set_filter_level(int level, u_char *err, size_t *errlen) +{ +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH + ngx_http_lua_log_ringbuf_t *ringbuf; + + ringbuf = ngx_cycle->intercept_error_log_data; + + if (ringbuf == NULL) { + *errlen = ngx_snprintf(err, *errlen, + "directive \"lua_capture_error_log\" is not set") + - err; + return NGX_ERROR; + } + + if (level > NGX_LOG_DEBUG || level < NGX_LOG_STDERR) { + *errlen = ngx_snprintf(err, *errlen, "bad log level: %d", level) + - err; + return NGX_ERROR; + } + + ringbuf->filter_level = level; + return NGX_OK; +#else + *errlen = ngx_snprintf(err, *errlen, + "missing the capture error log patch for nginx") + - err; + return NGX_ERROR; +#endif +} + + +int +ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, u_char *err, + size_t *errlen, double *log_time) +{ +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH + ngx_uint_t loglen; + + ngx_http_lua_log_ringbuf_t *ringbuf; + + ringbuf = ngx_cycle->intercept_error_log_data; + + if (ringbuf == NULL) { + *errlen = ngx_snprintf(err, *errlen, + "directive \"lua_capture_error_log\" is not set") + - err; + return NGX_ERROR; + } + + if (ringbuf->count == 0) { + return NGX_DONE; + } + + ngx_http_lua_log_ringbuf_read(ringbuf, loglevel, (void **) log, &loglen, + log_time); + return loglen; +#else + *errlen = ngx_snprintf(err, *errlen, + "missing the capture error log patch for nginx") + - err; + return NGX_ERROR; +#endif +} + + +int +ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r) +{ + ngx_log_t *log; + int log_level; + + if (r && r->connection && r->connection->log) { + log = r->connection->log; + + } else { + log = ngx_cycle->log; + } + + log_level = log->log_level; + if (log_level == NGX_LOG_DEBUG_ALL) { + log_level = NGX_LOG_DEBUG; + } + + return log_level; +} + +#endif + /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.h b/debian/modules/nginx-lua/src/ngx_http_lua_log.h index 42f1839..56cd771 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_log.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log.h @@ -13,6 +13,10 @@ void ngx_http_lua_inject_log_api(lua_State *L); +#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH +ngx_int_t ngx_http_lua_capture_log_handler(ngx_log_t *log, + ngx_uint_t level, u_char *buf, size_t n); +#endif #endif /* _NGX_HTTP_LUA_LOG_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c new file mode 100644 index 0000000..0464069 --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c @@ -0,0 +1,225 @@ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_lua_common.h" +#include "ngx_http_lua_log_ringbuf.h" + + +typedef struct { + double time; + unsigned len; + unsigned log_level; +} ngx_http_lua_log_ringbuf_header_t; + + +enum { + HEADER_LEN = sizeof(ngx_http_lua_log_ringbuf_header_t) +}; + + +static void *ngx_http_lua_log_ringbuf_next_header( + ngx_http_lua_log_ringbuf_t *rb); +static void ngx_http_lua_log_ringbuf_append( + ngx_http_lua_log_ringbuf_t *rb, int log_level, void *buf, int n); +static size_t ngx_http_lua_log_ringbuf_free_spaces( + ngx_http_lua_log_ringbuf_t *rb); + + +void +ngx_http_lua_log_ringbuf_init(ngx_http_lua_log_ringbuf_t *rb, void *buf, + size_t len) +{ + rb->data = buf; + rb->size = len; + + rb->tail = rb->data; + rb->head = rb->data; + rb->sentinel = rb->data + rb->size; + rb->count = 0; + rb->filter_level = NGX_LOG_DEBUG; + + return; +} + + +void +ngx_http_lua_log_ringbuf_reset(ngx_http_lua_log_ringbuf_t *rb) +{ + rb->tail = rb->data; + rb->head = rb->data; + rb->sentinel = rb->data + rb->size; + rb->count = 0; + + return; +} + + +/* + * get the next data header, it'll skip the useless data space or + * placehold data + */ +static void * +ngx_http_lua_log_ringbuf_next_header(ngx_http_lua_log_ringbuf_t *rb) +{ + /* useless data */ + if (rb->size - (rb->head - rb->data) < HEADER_LEN) + { + return rb->data; + } + + /* placehold data */ + if (rb->head >= rb->sentinel) { + return rb->data; + } + + return rb->head; +} + + +/* append data to ring buffer directly */ +static void +ngx_http_lua_log_ringbuf_append(ngx_http_lua_log_ringbuf_t *rb, + int log_level, void *buf, int n) +{ + ngx_http_lua_log_ringbuf_header_t *head; + ngx_time_t *tp; + + head = (ngx_http_lua_log_ringbuf_header_t *) rb->tail; + head->len = n; + head->log_level = log_level; + + tp = ngx_timeofday(); + head->time = tp->sec + tp->msec / 1000.0L; + + rb->tail += HEADER_LEN; + ngx_memcpy(rb->tail, buf, n); + rb->tail += n; + rb->count++; + + if (rb->tail > rb->sentinel) { + rb->sentinel = rb->tail; + } + + return; +} + + +/* throw away data at head */ +static void +ngx_http_lua_log_ringbuf_throw_away(ngx_http_lua_log_ringbuf_t *rb) +{ + ngx_http_lua_log_ringbuf_header_t *head; + + if (rb->count == 0) { + return; + } + + head = (ngx_http_lua_log_ringbuf_header_t *) rb->head; + + rb->head += HEADER_LEN + head->len; + rb->count--; + + if (rb->count == 0) { + ngx_http_lua_log_ringbuf_reset(rb); + } + + rb->head = ngx_http_lua_log_ringbuf_next_header(rb); + + return; +} + + +/* size of free spaces */ +static size_t +ngx_http_lua_log_ringbuf_free_spaces(ngx_http_lua_log_ringbuf_t *rb) +{ + if (rb->count == 0) { + return rb->size; + } + + if (rb->tail > rb->head) { + return rb->data + rb->size - rb->tail; + } + + return rb->head - rb->tail; +} + + +/* + * try to write log data to ring buffer, throw away old data + * if there was not enough free spaces. + */ +ngx_int_t +ngx_http_lua_log_ringbuf_write(ngx_http_lua_log_ringbuf_t *rb, int log_level, + void *buf, size_t n) +{ + if (n + HEADER_LEN > rb->size) { + return NGX_ERROR; + } + + if (ngx_http_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) { + /* if the right space is not enough, mark it as placehold data */ + if ((size_t)(rb->data + rb->size - rb->tail) < n + HEADER_LEN) { + + while (rb->head >= rb->tail && rb->count) { + /* head is after tail, so we will throw away all data between + * head and sentinel */ + ngx_http_lua_log_ringbuf_throw_away(rb); + } + + rb->sentinel = rb->tail; + rb->tail = rb->data; + } + + while (ngx_http_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) { + ngx_http_lua_log_ringbuf_throw_away(rb); + } + } + + ngx_http_lua_log_ringbuf_append(rb, log_level, buf, n); + + return NGX_OK; +} + + +/* read log from ring buffer, do reset if all of the logs were readed. */ +ngx_int_t +ngx_http_lua_log_ringbuf_read(ngx_http_lua_log_ringbuf_t *rb, int *log_level, + void **buf, size_t *n, double *log_time) +{ + ngx_http_lua_log_ringbuf_header_t *head; + + if (rb->count == 0) { + return NGX_ERROR; + } + + head = (ngx_http_lua_log_ringbuf_header_t *) rb->head; + + if (rb->head >= rb->sentinel) { + return NGX_ERROR; + } + + *log_level = head->log_level; + *n = head->len; + rb->head += HEADER_LEN; + *buf = rb->head; + rb->head += head->len; + + if (log_time) { + *log_time = head->time; + } + + rb->count--; + + if (rb->count == 0) { + ngx_http_lua_log_ringbuf_reset(rb); + } + + rb->head = ngx_http_lua_log_ringbuf_next_header(rb); + + return NGX_OK; +} diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h new file mode 100644 index 0000000..c9c2c2d --- /dev/null +++ b/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h @@ -0,0 +1,31 @@ + +#ifndef _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ +#define _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ + + +#include "ngx_http_lua_common.h" + + +typedef struct { + ngx_uint_t filter_level; + char *tail; /* writed point */ + char *head; /* readed point */ + char *data; /* buffer */ + char *sentinel; + size_t size; /* buffer total size */ + size_t count; /* count of logs */ +} ngx_http_lua_log_ringbuf_t; + + +void ngx_http_lua_log_ringbuf_init(ngx_http_lua_log_ringbuf_t *rb, + void *buf, size_t len); +void ngx_http_lua_log_ringbuf_reset(ngx_http_lua_log_ringbuf_t *rb); +ngx_int_t ngx_http_lua_log_ringbuf_read(ngx_http_lua_log_ringbuf_t *rb, + int *log_level, void **buf, size_t *n, double *log_time); +ngx_int_t ngx_http_lua_log_ringbuf_write(ngx_http_lua_log_ringbuf_t *rb, + int log_level, void *buf, size_t n); + + +#endif /* _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/nginx-lua/src/ngx_http_lua_module.c index 6e93c8e..9d914e8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_module.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_module.c @@ -28,6 +28,7 @@ #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_ssl_session_storeby.h" #include "ngx_http_lua_ssl_session_fetchby.h" +#include "ngx_http_lua_headers.h" static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); @@ -45,14 +46,6 @@ static char *ngx_http_lua_lowat_check(ngx_conf_t *cf, void *post, void *data); static ngx_int_t ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf); #endif -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) && (NGX_LINUX) -/* we cannot use "static" for this function since it may lead to compiler - * warnings */ -void ngx_http_lua_limit_data_segment(void); -# if !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) -static ngx_int_t ngx_http_lua_pre_config(ngx_conf_t *cf); -# endif -#endif static char *ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -101,6 +94,13 @@ static ngx_command_t ngx_http_lua_cmds[] = { 0, NULL }, + { ngx_string("lua_capture_error_log"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_lua_capture_error_log, + 0, + 0, + NULL }, + #if (NGX_PCRE) { ngx_string("lua_regex_cache_max_entries"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, @@ -592,13 +592,7 @@ static ngx_command_t ngx_http_lua_cmds[] = { ngx_http_module_t ngx_http_lua_module_ctx = { -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) \ - && (NGX_LINUX) \ - && !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) - ngx_http_lua_pre_config, /* preconfiguration */ -#else NULL, /* preconfiguration */ -#endif ngx_http_lua_init, /* postconfiguration */ ngx_http_lua_create_main_conf, /* create main configuration */ @@ -638,7 +632,7 @@ ngx_http_lua_init(ngx_conf_t *cf) volatile ngx_cycle_t *saved_cycle; ngx_http_core_main_conf_t *cmcf; ngx_http_lua_main_conf_t *lmcf; -#ifndef NGX_LUA_NO_FFI_API +#if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 ngx_pool_cleanup_t *cln; #endif @@ -730,6 +724,16 @@ ngx_http_lua_init(ngx_conf_t *cf) cln->handler = ngx_http_lua_sema_mm_cleanup; #endif +#if nginx_version >= 1011011 + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->data = lmcf; + cln->handler = ngx_http_lua_ngx_raw_header_cleanup; +#endif + if (lmcf->lua == NULL) { dd("initializing lua vm"); @@ -817,6 +821,7 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf) * lmcf->running_timers = 0; * lmcf->watcher = NULL; * lmcf->regex_cache_entries = 0; + * lmcf->jit_stack = NULL; * lmcf->shm_zones = NULL; * lmcf->init_handler = NULL; * lmcf->init_src = { 0, NULL }; @@ -955,7 +960,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) #ifdef LIBRESSL_VERSION_NUMBER ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "LibreSSL does not support ssl_ceritificate_by_lua*"); + "LibreSSL does not support ssl_certificate_by_lua*"); return NGX_CONF_ERROR; #else @@ -967,7 +972,7 @@ ngx_http_lua_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) # else ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "OpenSSL too old to support ssl_ceritificate_by_lua*"); + "OpenSSL too old to support ssl_certificate_by_lua*"); return NGX_CONF_ERROR; # endif @@ -1267,37 +1272,6 @@ ngx_http_lua_set_ssl(ngx_conf_t *cf, ngx_http_lua_loc_conf_t *llcf) #endif /* NGX_HTTP_SSL */ -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) \ - && (NGX_LINUX) \ - && !(NGX_HTTP_LUA_HAVE_CONSTRUCTOR) -static ngx_int_t -ngx_http_lua_pre_config(ngx_conf_t *cf) -{ - ngx_http_lua_limit_data_segment(); - return NGX_OK; -} -#endif - - -/* - * we simply assume that LuaJIT is used. it does little harm when the - * standard Lua 5.1 interpreter is used instead. - */ -#if (NGX_HTTP_LUA_HAVE_MMAP_SBRK) && (NGX_LINUX) -# if (NGX_HTTP_LUA_HAVE_CONSTRUCTOR) -__attribute__((constructor)) -# endif -void -ngx_http_lua_limit_data_segment(void) -{ - if (sbrk(0) < (void *) 0x40000000LL) { - mmap(ngx_align_ptr(sbrk(0), getpagesize()), 1, PROT_READ, - MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0); - } -} -#endif - - static char * ngx_http_lua_malloc_trim(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c index d882061..80519ec 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.c @@ -17,14 +17,6 @@ #include "ngx_http_lua_script.h" #include "ngx_http_lua_pcrefix.h" #include "ngx_http_lua_util.h" -#include - - -#if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21) -# define LUA_HAVE_PCRE_JIT 1 -#else -# define LUA_HAVE_PCRE_JIT 0 -#endif #if (PCRE_MAJOR >= 6) @@ -42,6 +34,8 @@ #define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100) +#define NGX_LUA_RE_MIN_JIT_STACK_SIZE 32 * 1024 + typedef struct { #ifndef NGX_LUA_NO_FFI_API @@ -364,6 +358,10 @@ ngx_http_lua_ngx_re_match_helper(lua_State *L, int wantcaps) sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); + if (sd && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } + ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) @@ -826,6 +824,10 @@ ngx_http_lua_ngx_re_gmatch(lua_State *L) sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg); + if (sd && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } + ngx_http_lua_pcre_malloc_done(old_pool); # if (NGX_DEBUG) @@ -1922,6 +1924,60 @@ error: } +ngx_int_t +ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, + size_t *errstr_size) +{ +#if LUA_HAVE_PCRE_JIT + + ngx_http_lua_main_conf_t *lmcf; + ngx_pool_t *pool, *old_pool; + + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + + if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) { + size = NGX_LUA_RE_MIN_JIT_STACK_SIZE; + } + + pool = lmcf->pool; + + dd("server pool %p", lmcf->pool); + + if (lmcf->jit_stack) { + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + pcre_jit_stack_free(lmcf->jit_stack); + + ngx_http_lua_pcre_malloc_done(old_pool); + } + + old_pool = ngx_http_lua_pcre_malloc_init(pool); + + lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE, + size); + + ngx_http_lua_pcre_malloc_done(old_pool); + + if (lmcf->jit_stack == NULL) { + *errstr_size = ngx_snprintf(errstr, *errstr_size, + "pcre jit stack allocation failed") + - errstr; + return NGX_ERROR; + } + + return NGX_OK; + +#else /* LUA_HAVE_PCRE_JIT */ + + *errstr_size = ngx_snprintf(errstr, *errstr_size, + "no pcre jit support found") - errstr; + return NGX_ERROR; + +#endif /* LUA_HAVE_PCRE_JIT */ +} + + void ngx_http_lua_inject_regex_api(lua_State *L) { @@ -2170,6 +2226,9 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, goto error; } + lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, + ngx_http_lua_module); + #if (LUA_HAVE_PCRE_JIT) if (flags & NGX_LUA_RE_MODE_JIT) { @@ -2205,10 +2264,11 @@ ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, ngx_http_lua_pcre_malloc_done(old_pool); } -#endif /* LUA_HAVE_PCRE_JIT */ + if (sd && lmcf->jit_stack) { + pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack); + } - lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle, - ngx_http_lua_module); +#endif /* LUA_HAVE_PCRE_JIT */ if (sd && lmcf && lmcf->regex_match_limit > 0) { sd->flags |= PCRE_EXTRA_MATCH_LIMIT; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.h b/debian/modules/nginx-lua/src/ngx_http_lua_regex.h index f5f8e2f..03dffb8 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_regex.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_regex.h @@ -14,6 +14,8 @@ #if (NGX_PCRE) void ngx_http_lua_inject_regex_api(lua_State *L); +ngx_int_t ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr, + size_t *errstr_size); #endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c index 8a3f832..eda0141 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c @@ -387,8 +387,8 @@ ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, return NGX_ERROR; } - /* we keep the order, will resume the older waited firtly - * in ngx_http_lua_sema_handler + /* we keep the order, will first resume the thread waiting for the + * longest time in ngx_http_lua_sema_handler */ if (ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) { @@ -557,8 +557,11 @@ ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem) return; } - if (!ngx_queue_empty(&sem->wait_queue)) { - ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, + if (!ngx_terminate + && !ngx_quit + && !ngx_queue_empty(&sem->wait_queue)) + { + ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "in lua semaphore gc wait queue is" " not empty while the semaphore %p is being " "destroyed", sem); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c index 4c0d016..ffee97f 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c @@ -72,10 +72,25 @@ ngx_http_lua_ngx_sleep(lua_State *L) coctx->sleep.data = coctx; coctx->sleep.log = r->connection->log; - dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, - (int) r->uri.len, r->uri.data); + if (delay == 0) { +#ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH + dd("posting 0 sec sleep event to head of delayed queue"); - ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); + coctx->sleep.delayed = 1; + ngx_post_event(&coctx->sleep, &ngx_posted_delayed_events); +#else + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx.sleep(0)" + " called without delayed events patch, this will" + " hurt performance"); + ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); +#endif + + } else { + dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay, + (int) r->uri.len, r->uri.data); + + ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay); + } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua ready to sleep for %d ms", delay); @@ -147,6 +162,15 @@ ngx_http_lua_sleep_cleanup(void *data) ngx_del_timer(&coctx->sleep); } + +#ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH + if (coctx->sleep.posted) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "lua clean up the posted event for pending ngx.sleep"); + + ngx_delete_posted_event(&coctx->sleep); + } +#endif } diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c index 6db6e2d..382a94d 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c @@ -69,8 +69,6 @@ static void ngx_http_lua_socket_dummy_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); static ngx_int_t ngx_http_lua_socket_tcp_read(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u); -static void ngx_http_lua_socket_read_handler(ngx_http_request_t *r, - ngx_http_lua_socket_tcp_upstream_t *u); static int ngx_http_lua_socket_tcp_receive_retval_handler(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, lua_State *L); static ngx_int_t ngx_http_lua_socket_read_line(void *data, ssize_t bytes); @@ -501,6 +499,12 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) n--; } + /* the fourth argument is not a table */ + if (n == 4) { + lua_pop(L, 1); + n--; + } + if (n == 3) { port = luaL_checkinteger(L, 3); @@ -1208,11 +1212,12 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) ngx_http_lua_socket_tcp_upstream_t *u; - /* Lua function arguments: self [,session] [,host] [,verify] */ + /* Lua function arguments: self [,session] [,host] [,verify] + [,send_status_req] */ n = lua_gettop(L); if (n < 1 || n > 5) { - return luaL_error(L, "ngx.socket connect: expecting 1 ~ 5 " + return luaL_error(L, "ngx.socket sslhandshake: expecting 1 ~ 5 " "arguments (including the object), but seen %d", n); } @@ -1327,7 +1332,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if (SSL_set_tlsext_host_name(c->ssl->connection, name.data) + if (SSL_set_tlsext_host_name(c->ssl->connection, + (char *) name.data) == 0) { lua_pushnil(L); @@ -4412,15 +4418,18 @@ ngx_http_lua_req_socket_rev_handler(ngx_http_request_t *r) ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); if (ctx == NULL) { + r->read_event_handler = ngx_http_block_reading; return; } u = ctx->downstream; - if (u) { - u->read_event_handler(r, u); + if (u == NULL || u->peer.connection == NULL) { + r->read_event_handler = ngx_http_block_reading; + return; } -} + u->read_event_handler(r, u); +} static int ngx_http_lua_socket_tcp_getreusedtimes(lua_State *L) diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h index 7a245ff..acb8c4b 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h @@ -12,6 +12,8 @@ #if (NGX_HTTP_SSL) + + typedef struct { ngx_connection_t *connection; /* original true connection */ ngx_http_request_t *request; /* fake request */ @@ -31,7 +33,6 @@ typedef struct { unsigned entered_cert_handler:1; unsigned entered_sess_fetch_handler:1; } ngx_http_lua_ssl_ctx_t; -#endif ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); @@ -40,4 +41,7 @@ ngx_int_t ngx_http_lua_ssl_init(ngx_log_t *log); extern int ngx_http_lua_ssl_ctx_index; +#endif + + #endif /* _NGX_HTTP_LUA_SSL_H_INCLUDED_ */ diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c index aca4735..c3591d1 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c @@ -193,6 +193,7 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) ngx_http_lua_srv_conf_t *lscf; ngx_http_core_loc_conf_t *clcf; ngx_http_lua_ssl_ctx_t *cctx; + ngx_http_core_srv_conf_t *cscf; c = ngx_ssl_get_connection(ssl_conn); @@ -298,6 +299,16 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c->log->action = "loading SSL certificate by lua"; + if (lscf->srv.ssl_cert_handler == NULL) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "no ssl_certificate_by_lua* defined in " + "server %V", &cscf->server_name); + + goto failed; + } + rc = lscf->srv.ssl_cert_handler(r, lscf, L); if (rc >= NGX_OK || rc == NGX_ERROR) { @@ -453,7 +464,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } } else { @@ -470,7 +483,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } /* move code closure to new coroutine */ @@ -494,7 +509,9 @@ ngx_http_lua_ssl_cert_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } cln->handler = ngx_http_lua_request_cleanup_handler; @@ -1129,7 +1146,11 @@ ngx_http_lua_ffi_set_cert(ngx_http_request_t *r, # else +#ifdef OPENSSL_IS_BORINGSSL + size_t i; +#else int i; +#endif X509 *x509 = NULL; ngx_ssl_conn_t *ssl_conn; STACK_OF(X509) *chain = cdata; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c index 3904aa8..31b4f24 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c @@ -490,7 +490,6 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, dd("set ocsp resp: resp_len=%d", (int) resp_len); (void) SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp_len); - ssl_conn->tlsext_status_expected = 1; return NGX_OK; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c index 4c450b5..556b732 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -107,7 +107,7 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -468,7 +468,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } } else { @@ -485,7 +487,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "lua: failed to create new coroutine to handle request"); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } /* move code closure to new coroutine */ @@ -509,7 +513,9 @@ ngx_http_lua_ssl_sess_fetch_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx->cleanup == NULL) { cln = ngx_http_cleanup_add(r, 0); if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } cln->handler = ngx_http_lua_request_cleanup_handler; diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c index b5596bc..bae8273 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -105,7 +105,7 @@ ngx_http_lua_ssl_sess_store_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, dd("enter"); - /* must specifiy a content handler */ + /* must specify a content handler */ if (cmd->post == NULL) { return NGX_CONF_ERROR; } @@ -351,7 +351,9 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) if (ctx == NULL) { ctx = ngx_http_lua_create_ctx(r); if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + rc = NGX_ERROR; + ngx_http_lua_finalize_request(r, rc); + return rc; } } else { @@ -386,7 +388,7 @@ ngx_http_lua_ssl_sess_store_by_chunk(lua_State *L, ngx_http_request_t *r) dd("rc == %d", (int) rc); if (rc != 0) { - /* error occured when running loaded code */ + /* error occurred when running loaded code */ err_msg = (u_char *) lua_tolstring(L, -1, &len); if (err_msg == NULL) { diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/nginx-lua/src/ngx_http_lua_string.c index 22b4c00..239b232 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_string.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_string.c @@ -125,12 +125,13 @@ ngx_http_lua_ngx_escape_uri(lua_State *L) return 1; } - escape = 2 * ngx_http_lua_escape_uri(NULL, src, len, NGX_ESCAPE_URI); + escape = 2 * ngx_http_lua_escape_uri(NULL, src, len, + NGX_ESCAPE_URI_COMPONENT); if (escape) { dlen = escape + len; dst = lua_newuserdata(L, dlen); - ngx_http_lua_escape_uri(dst, src, len, NGX_ESCAPE_URI); + ngx_http_lua_escape_uri(dst, src, len, NGX_ESCAPE_URI_COMPONENT); lua_pushlstring(L, (char *) dst, dlen); } @@ -751,14 +752,14 @@ size_t ngx_http_lua_ffi_uri_escaped_length(const u_char *src, size_t len) { return len + 2 * ngx_http_lua_escape_uri(NULL, (u_char *) src, len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } void ngx_http_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst) { - ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI); + ngx_http_lua_escape_uri(dst, (u_char *) src, len, NGX_ESCAPE_URI_COMPONENT); } #endif diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c index 01b4777..596b2f7 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_timer.c @@ -21,11 +21,6 @@ typedef struct { void **srv_conf; void **loc_conf; - /* event ident must be after 3 words (i.e. 3 pointers' size) as in - * ngx_connection_t. and we use the Lua coroutine reference number as - * the event ident */ - int co_ref; - unsigned premature; /* :1 */ lua_State *co; ngx_pool_t *pool; @@ -36,12 +31,18 @@ typedef struct { ngx_http_lua_main_conf_t *lmcf; ngx_http_lua_vm_state_t *vm_state; + int co_ref; + unsigned delay:31; + unsigned premature:1; } ngx_http_lua_timer_ctx_t; static int ngx_http_lua_ngx_timer_at(lua_State *L); +static int ngx_http_lua_ngx_timer_every(lua_State *L); +static int ngx_http_lua_ngx_timer_helper(lua_State *L, int every); static int ngx_http_lua_ngx_timer_running_count(lua_State *L); static int ngx_http_lua_ngx_timer_pending_count(lua_State *L); +static ngx_int_t ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx); static void ngx_http_lua_timer_handler(ngx_event_t *ev); static u_char *ngx_http_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len); @@ -51,11 +52,14 @@ static void ngx_http_lua_abort_pending_timers(ngx_event_t *ev); void ngx_http_lua_inject_timer_api(lua_State *L) { - lua_createtable(L, 0 /* narr */, 3 /* nrec */); /* ngx.timer. */ + lua_createtable(L, 0 /* narr */, 4 /* nrec */); /* ngx.timer. */ lua_pushcfunction(L, ngx_http_lua_ngx_timer_at); lua_setfield(L, -2, "at"); + lua_pushcfunction(L, ngx_http_lua_ngx_timer_every); + lua_setfield(L, -2, "every"); + lua_pushcfunction(L, ngx_http_lua_ngx_timer_running_count); lua_setfield(L, -2, "running_count"); @@ -106,6 +110,24 @@ ngx_http_lua_ngx_timer_pending_count(lua_State *L) static int ngx_http_lua_ngx_timer_at(lua_State *L) +{ + return ngx_http_lua_ngx_timer_helper(L, 0); +} + + +/* + * TODO: return a timer handler instead which can be passed to + * the ngx.timer.cancel method to cancel the timer. + */ +static int +ngx_http_lua_ngx_timer_every(lua_State *L) +{ + return ngx_http_lua_ngx_timer_helper(L, 1); +} + + +static int +ngx_http_lua_ngx_timer_helper(lua_State *L, int every) { int nargs, co_ref; u_char *p; @@ -134,6 +156,10 @@ ngx_http_lua_ngx_timer_at(lua_State *L) delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000); + if (every && delay == 0) { + return luaL_error(L, "delay cannot be zero"); + } + luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2, "Lua function expected"); @@ -233,7 +259,7 @@ ngx_http_lua_ngx_timer_at(lua_State *L) lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); lua_rawget(L, LUA_REGISTRYINDEX); - /* L stack: time func [args] thread corountines */ + /* L stack: time func [args] thread coroutines */ lua_pushvalue(L, -2); @@ -265,6 +291,8 @@ ngx_http_lua_ngx_timer_at(lua_State *L) tctx = (ngx_http_lua_timer_ctx_t *) p; + tctx->delay = every ? delay : 0; + tctx->premature = 0; tctx->co_ref = co_ref; tctx->co = co; @@ -338,6 +366,164 @@ nomem: } +static ngx_int_t +ngx_http_lua_timer_copy(ngx_http_lua_timer_ctx_t *old_tctx) +{ + int nargs, co_ref, i; + u_char *p; + lua_State *vm; /* the main thread */ + lua_State *co; + lua_State *L; + ngx_event_t *ev = NULL; + ngx_http_lua_timer_ctx_t *tctx = NULL; + ngx_http_lua_main_conf_t *lmcf; + + /* L stack: func [args] */ + L = old_tctx->co; + + lmcf = old_tctx->lmcf; + + vm = old_tctx->vm_state ? old_tctx->vm_state->vm : lmcf->lua; + + co = lua_newthread(vm); + + lua_createtable(co, 0, 0); /* the new globals table */ + + /* co stack: global_tb */ + + lua_createtable(co, 0, 1); /* the metatable */ + ngx_http_lua_get_globals_table(co); + lua_setfield(co, -2, "__index"); + lua_setmetatable(co, -2); + + /* co stack: global_tb */ + + ngx_http_lua_set_globals_table(co); + + /* co stack: */ + + dd("stack top: %d", lua_gettop(L)); + + lua_xmove(vm, L, 1); /* move coroutine from main thread to L */ + + /* L stack: func [args] thread */ + /* vm stack: empty */ + + lua_pushvalue(L, 1); /* copy entry function to top of L*/ + + /* L stack: func [args] thread func */ + + lua_xmove(L, co, 1); /* move entry function from L to co */ + + /* L stack: func [args] thread */ + /* co stack: func */ + + ngx_http_lua_get_globals_table(co); + lua_setfenv(co, -2); + + /* co stack: func */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + + /* L stack: func [args] thread coroutines */ + + lua_pushvalue(L, -2); + + /* L stack: func [args] thread coroutines thread */ + + co_ref = luaL_ref(L, -2); + lua_pop(L, 2); + + /* L stack: func [args] */ + + nargs = lua_gettop(L); + if (nargs > 1) { + for (i = 2; i <= nargs; i++) { + lua_pushvalue(L, i); + } + + /* L stack: func [args] [args] */ + + lua_xmove(L, co, nargs - 1); + + /* L stack: func [args] */ + /* co stack: func [args] */ + } + + p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_http_lua_timer_ctx_t), + ngx_cycle->log); + if (p == NULL) { + goto nomem; + } + + ev = (ngx_event_t *) p; + + ngx_memzero(ev, sizeof(ngx_event_t)); + + p += sizeof(ngx_event_t); + + tctx = (ngx_http_lua_timer_ctx_t *) p; + + ngx_memcpy(tctx, old_tctx, sizeof(ngx_http_lua_timer_ctx_t)); + + tctx->co_ref = co_ref; + tctx->co = co; + + tctx->pool = ngx_create_pool(128, ngx_cycle->log); + if (tctx->pool == NULL) { + goto nomem; + } + + if (tctx->client_addr_text.len) { + tctx->client_addr_text.data = ngx_palloc(tctx->pool, + tctx->client_addr_text.len); + if (tctx->client_addr_text.data == NULL) { + goto nomem; + } + + ngx_memcpy(tctx->client_addr_text.data, old_tctx->client_addr_text.data, + tctx->client_addr_text.len); + } + + if (tctx->vm_state) { + tctx->vm_state->count++; + } + + ev->handler = ngx_http_lua_timer_handler; + ev->data = tctx; + ev->log = ngx_cycle->log; + + lmcf->pending_timers++; + + ngx_add_timer(ev, tctx->delay); + + return NGX_OK; + +nomem: + + if (tctx && tctx->pool) { + ngx_destroy_pool(tctx->pool); + } + + if (ev) { + ngx_free(ev); + } + + /* L stack: func [args] */ + + lua_pushlightuserdata(L, &ngx_http_lua_coroutines_key); + lua_rawget(L, LUA_REGISTRYINDEX); + luaL_unref(L, -1, co_ref); + + /* L stack: func [args] coroutines */ + + lua_pop(L, 1); + + return NGX_ERROR; +} + + static void ngx_http_lua_timer_handler(ngx_event_t *ev) { @@ -364,6 +550,15 @@ ngx_http_lua_timer_handler(ngx_event_t *ev) lmcf->pending_timers--; + if (!ngx_exiting && tctx.delay > 0) { + rc = ngx_http_lua_timer_copy(&tctx); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "failed to create the next timer of delay %ud ms", + (unsigned) tctx.delay); + } + } + if (lmcf->running_timers >= lmcf->max_running_timers) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "%i lua_max_running_timers are not enough", diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/nginx-lua/src/ngx_http_lua_util.c index 7f59833..c7bee3e 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_util.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_util.c @@ -51,6 +51,7 @@ #include "ngx_http_lua_socket_tcp.h" #include "ngx_http_lua_ssl_certby.h" #include "ngx_http_lua_ssl.h" +#include "ngx_http_lua_log_ringbuf.h" #if 1 @@ -918,7 +919,11 @@ ngx_http_lua_request_cleanup(ngx_http_lua_ctx_t *ctx, int forcible) #if 1 if (r->connection->fd == (ngx_socket_t) -1) { /* being a fake request */ - lmcf->running_timers--; + + if (ctx->context == NGX_HTTP_LUA_CONTEXT_TIMER) { + /* being a timer handler */ + lmcf->running_timers--; + } } #endif @@ -1835,6 +1840,26 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* ~}| {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 */ + }; + + /* not ALPHA, DIGIT, "-", ".", "_", "~" */ + + static uint32_t uri_component[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xfc00987d, /* 1111 1100 0000 0000 1001 1000 0111 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + 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 */ @@ -1904,8 +1929,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* mail_auth is the same as memcached */ static uint32_t *map[] = - { uri, args, html, refresh, memcached, memcached }; - + { uri, args, uri_component, html, refresh, memcached, memcached }; escape = map[type]; @@ -2316,7 +2340,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, key = (u_char *) lua_tolstring(L, -2, &key_len); key_escape = 2 * ngx_http_lua_escape_uri(NULL, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); total_escape += key_escape; switch (lua_type(L, -1)) { @@ -2325,7 +2349,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, value = (u_char *) lua_tolstring(L, -1, &value_len); total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); len += key_len + value_len + (sizeof("=") - 1); n++; @@ -2366,7 +2390,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); len += key_len + value_len + (sizeof("=") - 1); } @@ -2423,7 +2447,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { dd("shortcut: no escape required"); @@ -2437,7 +2462,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { p = ngx_copy(p, value, value_len); @@ -2456,7 +2482,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (lua_toboolean(L, -1)) { if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2484,7 +2510,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2503,7 +2529,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { dd("shortcut: no escape required"); @@ -2519,7 +2546,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT + ); } else { p = ngx_copy(p, value, value_len); diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c index ff09b5b..e1cfec4 100644 --- a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c +++ b/debian/modules/nginx-lua/src/ngx_http_lua_worker.c @@ -13,6 +13,9 @@ #include "ngx_http_lua_worker.h" +#define NGX_PROCESS_PRIVILEGED_AGENT 99 + + static int ngx_http_lua_ngx_worker_exiting(lua_State *L); static int ngx_http_lua_ngx_worker_pid(lua_State *L); static int ngx_http_lua_ngx_worker_id(lua_State *L); @@ -130,4 +133,46 @@ ngx_http_lua_ffi_worker_count(void) return (int) ccf->worker_processes; } + + +int +ngx_http_lua_ffi_get_process_type(void) +{ +#if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32 + if (ngx_process == NGX_PROCESS_HELPER) { + if (ngx_is_privileged_agent) { + return NGX_PROCESS_PRIVILEGED_AGENT; + } + } +#endif + + return ngx_process; +} + + +int +ngx_http_lua_ffi_enable_privileged_agent(char **err) +{ +#ifdef HAVE_PRIVILEGED_PROCESS_PATCH + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + ccf->privileged_agent = 1; + + return NGX_OK; + +#else + *err = "missing privileged agent process patch in the nginx core"; + return NGX_ERROR; +#endif +} + + +void +ngx_http_lua_ffi_process_signal_graceful_exit(void) +{ + ngx_quit = 1; +} #endif diff --git a/debian/modules/nginx-lua/t/000--init.t b/debian/modules/nginx-lua/t/000--init.t index 364334f..ad2d70e 100644 --- a/debian/modules/nginx-lua/t/000--init.t +++ b/debian/modules/nginx-lua/t/000--init.t @@ -84,4 +84,3 @@ GET /flush --- timeout: 10 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/000-sanity.t b/debian/modules/nginx-lua/t/000-sanity.t index 3f66752..87854ef 100644 --- a/debian/modules/nginx-lua/t/000-sanity.t +++ b/debian/modules/nginx-lua/t/000-sanity.t @@ -31,4 +31,3 @@ GET /lua GET /lua --- response_body helloworld - diff --git a/debian/modules/nginx-lua/t/001-set.t b/debian/modules/nginx-lua/t/001-set.t index 2295a2d..ba8f22c 100644 --- a/debian/modules/nginx-lua/t/001-set.t +++ b/debian/modules/nginx-lua/t/001-set.t @@ -795,4 +795,3 @@ GET /lua?a=1&b=2 --- error_code: 500 --- error_log eval qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/ - diff --git a/debian/modules/nginx-lua/t/002-content.t b/debian/modules/nginx-lua/t/002-content.t index e6cb62d..3f2460e 100644 --- a/debian/modules/nginx-lua/t/002-content.t +++ b/debian/modules/nginx-lua/t/002-content.t @@ -836,4 +836,3 @@ GET /lua --- error_code: 500 --- error_log eval qr/failed to load inlined Lua code: / - diff --git a/debian/modules/nginx-lua/t/003-errors.t b/debian/modules/nginx-lua/t/003-errors.t index 764300a..ad3a506 100644 --- a/debian/modules/nginx-lua/t/003-errors.t +++ b/debian/modules/nginx-lua/t/003-errors.t @@ -126,4 +126,3 @@ GET /main GET /main --- response_body 500 - diff --git a/debian/modules/nginx-lua/t/004-require.t b/debian/modules/nginx-lua/t/004-require.t index 3250b2f..ec74116 100644 --- a/debian/modules/nginx-lua/t/004-require.t +++ b/debian/modules/nginx-lua/t/004-require.t @@ -208,4 +208,3 @@ GET /ndk GET /ndk --- response_body %20 - diff --git a/debian/modules/nginx-lua/t/005-exit.t b/debian/modules/nginx-lua/t/005-exit.t index 781531f..a5a28b3 100644 --- a/debian/modules/nginx-lua/t/005-exit.t +++ b/debian/modules/nginx-lua/t/005-exit.t @@ -723,4 +723,3 @@ GET /t --- response_body --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/006-escape.t b/debian/modules/nginx-lua/t/006-escape.t index 7b26bba..a21d3cb 100644 --- a/debian/modules/nginx-lua/t/006-escape.t +++ b/debian/modules/nginx-lua/t/006-escape.t @@ -3,9 +3,8 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -#repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 2 + 2); no_long_string(); @@ -181,3 +180,20 @@ GET /t --- response_body [32] + + +=== TEST 14: reserved chars +--- config + location /lua { + content_by_lua_block { + ngx.say(ngx.escape_uri("-_.!~*'()")) + ngx.say(ngx.escape_uri(",$@|`")) + } + } +--- request +GET /lua +--- response_body +-_.!~*'() +%2C%24%40%7C%60 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/007-md5.t b/debian/modules/nginx-lua/t/007-md5.t index 501e3af..2ae9efb 100644 --- a/debian/modules/nginx-lua/t/007-md5.t +++ b/debian/modules/nginx-lua/t/007-md5.t @@ -100,4 +100,3 @@ d41d8cd98f00b204e9800998ecf8427e GET /md5 --- response_body 6c8349cc7260ae62e3b1396831a8398f - diff --git a/debian/modules/nginx-lua/t/008-today.t b/debian/modules/nginx-lua/t/008-today.t index 54bd949..ec2f433 100644 --- a/debian/modules/nginx-lua/t/008-today.t +++ b/debian/modules/nginx-lua/t/008-today.t @@ -36,4 +36,3 @@ GET /today --- request GET /today --- response_body_like: ^\d{4}-\d{2}-\d{2}$ - diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/nginx-lua/t/009-log.t index 0c6a9a5..68c057f 100644 --- a/debian/modules/nginx-lua/t/009-log.t +++ b/debian/modules/nginx-lua/t/009-log.t @@ -542,4 +542,3 @@ ok [error] --- error_log eval "2: hello\0world, client: " - diff --git a/debian/modules/nginx-lua/t/010-request_body.t b/debian/modules/nginx-lua/t/010-request_body.t index 2640a54..e669d94 100644 --- a/debian/modules/nginx-lua/t/010-request_body.t +++ b/debian/modules/nginx-lua/t/010-request_body.t @@ -270,4 +270,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug - diff --git a/debian/modules/nginx-lua/t/012-now.t b/debian/modules/nginx-lua/t/012-now.t index abcb735..5885187 100644 --- a/debian/modules/nginx-lua/t/012-now.t +++ b/debian/modules/nginx-lua/t/012-now.t @@ -116,4 +116,3 @@ GET /time --- request GET /time --- response_body_like: ^\d{10,}(\.\d{1,3})?$ - diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/nginx-lua/t/014-bugs.t index 44337e3..9aadff0 100644 --- a/debian/modules/nginx-lua/t/014-bugs.t +++ b/debian/modules/nginx-lua/t/014-bugs.t @@ -849,7 +849,7 @@ ok "lua_package_path '$::HtmlDir/?.lua;./?.lua';" --- config location /t { - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; set $myhost 'agentzh.org.'; proxy_pass http://$myhost/misc/.vimrc; } @@ -1018,4 +1018,3 @@ write timer set: 1 --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/nginx-lua/t/016-resp-header.t index 179b411..1fae292 100644 --- a/debian/modules/nginx-lua/t/016-resp-header.t +++ b/debian/modules/nginx-lua/t/016-resp-header.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 38); +plan tests => repeat_each() * (blocks() * 3 + 41); #no_diff(); no_long_string(); @@ -1441,3 +1441,71 @@ Content-Type: ; blah test --- no_error_log [error] + + + +=== TEST 69: return the matched content-type instead of default_type +--- http_config +types { + image/png png; +} +--- config +location /set/ { + default_type text/html; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + } +} +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] + + + +=== TEST 70: always return the matched content-type +--- config + location /set/ { + default_type "image/png"; + content_by_lua_block { + ngx.say(ngx.header["content-type"]) + ngx.say(ngx.header["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +image/png +--- no_error_log +[error] + + + +=== TEST 71: return the matched content-type after ngx.resp.get_headers() +--- http_config +types { + image/png png; +} +--- config + location /set/ { + default_type text/html; + content_by_lua_block { + local h = ngx.resp.get_headers() + ngx.say(h["content-type"]) + } + } +--- request +GET /set/hello.png +--- response_headers +Content-Type: image/png +--- response_body +image/png +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/017-exec.t b/debian/modules/nginx-lua/t/017-exec.t index 4c7a918..535c4ab 100644 --- a/debian/modules/nginx-lua/t/017-exec.t +++ b/debian/modules/nginx-lua/t/017-exec.t @@ -572,4 +572,3 @@ hello, bah ["dummy", "dummy"] --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/018-ndk.t b/debian/modules/nginx-lua/t/018-ndk.t index d68306b..1429377 100644 --- a/debian/modules/nginx-lua/t/018-ndk.t +++ b/debian/modules/nginx-lua/t/018-ndk.t @@ -171,4 +171,3 @@ ok foo = a b --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/019-const.t b/debian/modules/nginx-lua/t/019-const.t index fe79bfb..4f9c764 100644 --- a/debian/modules/nginx-lua/t/019-const.t +++ b/debian/modules/nginx-lua/t/019-const.t @@ -44,4 +44,3 @@ GET /read GET /read --- response_body 504 - diff --git a/debian/modules/nginx-lua/t/021-cookie-time.t b/debian/modules/nginx-lua/t/021-cookie-time.t index c00bbea..b05e401 100644 --- a/debian/modules/nginx-lua/t/021-cookie-time.t +++ b/debian/modules/nginx-lua/t/021-cookie-time.t @@ -43,4 +43,3 @@ Thu, 18-Nov-10 11:27:35 GMT GET /lua --- response_body Thu, 18-Nov-10 11:27:35 GMT - diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/nginx-lua/t/022-redirect.t index 57c7add..fae39e3 100644 --- a/debian/modules/nginx-lua/t/022-redirect.t +++ b/debian/modules/nginx-lua/t/022-redirect.t @@ -84,7 +84,7 @@ GET /read --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log -only ngx.HTTP_MOVED_TEMPORARILY, ngx.HTTP_MOVED_PERMANENTLY, and ngx.HTTP_TEMPORARY_REDIRECT are allowed +only ngx.HTTP_MOVED_TEMPORARILY, ngx.HTTP_MOVED_PERMANENTLY, ngx.HTTP_SEE_OTHER, and ngx.HTTP_TEMPORARY_REDIRECT are allowed @@ -218,3 +218,54 @@ GET /read Location: http://agentzh.org/foo?a=b&c=d --- response_body_like: 307 Temporary Redirect --- error_code: 307 + + + +=== TEST 12: explicit 303 +--- config + location /read { + content_by_lua_block { + ngx.redirect("http://agentzh.org/foo", ngx.HTTP_SEE_OTHER); + ngx.say("hi") + } + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo +--- response_body_like: 303 See Other +--- error_code: 303 + + + +=== TEST 13: explicit 303 with args +--- config + location /read { + content_by_lua_block { + ngx.redirect("http://agentzh.org/foo?a=b&c=d", ngx.HTTP_SEE_OTHER); + ngx.say("hi") + } + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo?a=b&c=d +--- response_body_like: 303 See Other +--- error_code: 303 + + + +=== TEST 14: explicit 303 +--- config + location /read { + content_by_lua_block { + ngx.redirect("http://agentzh.org/foo?a=b&c=d", 303); + ngx.say("hi") + } + } +--- request +GET /read +--- response_headers +Location: http://agentzh.org/foo?a=b&c=d +--- response_body_like: 303 See Other +--- error_code: 303 diff --git a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t b/debian/modules/nginx-lua/t/023-rewrite/client-abort.t index e970802..117d17e 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/client-abort.t @@ -848,4 +848,3 @@ delete thread 1 --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/exec.t b/debian/modules/nginx-lua/t/023-rewrite/exec.t index a063b5b..bd97968 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/exec.t +++ b/debian/modules/nginx-lua/t/023-rewrite/exec.t @@ -376,4 +376,3 @@ ngx.exec("@proxy") GET /main --- response_body hello, bah - diff --git a/debian/modules/nginx-lua/t/023-rewrite/exit.t b/debian/modules/nginx-lua/t/023-rewrite/exit.t index 9d292f7..39ea5cb 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/exit.t +++ b/debian/modules/nginx-lua/t/023-rewrite/exit.t @@ -595,4 +595,3 @@ F(ngx_http_send_header) { --- error_code: 204 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/mixed.t b/debian/modules/nginx-lua/t/023-rewrite/mixed.t index 1156567..0f742b2 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/mixed.t +++ b/debian/modules/nginx-lua/t/023-rewrite/mixed.t @@ -167,4 +167,3 @@ world\x03\x04\xff hello\x00\x01\x02 world\x03\x04\xff " - diff --git a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t b/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t index 44629b0..083ec78 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t +++ b/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t @@ -392,4 +392,3 @@ res4.status = 201 res4.body = STORED\r " - diff --git a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t index aca2ab6..336b7ce 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t +++ b/debian/modules/nginx-lua/t/023-rewrite/on-abort.t @@ -654,4 +654,3 @@ delete thread 2 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/nginx-lua/t/023-rewrite/redirect.t index 8843f1a..99f3fd4 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/redirect.t @@ -122,4 +122,3 @@ GET /read --- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 - diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-body.t b/debian/modules/nginx-lua/t/023-rewrite/req-body.t index 2f42e0a..13bdcb2 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-body.t @@ -221,4 +221,3 @@ hiya, world"] --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t b/debian/modules/nginx-lua/t/023-rewrite/req-socket.t index 34aedaa..87cbbbe 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/req-socket.t @@ -532,4 +532,3 @@ Expect: 100-Continue \breceived: hello\b.*?\breceived: worl\b --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/request_body.t b/debian/modules/nginx-lua/t/023-rewrite/request_body.t index 0594001..b867d3a 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/request_body.t +++ b/debian/modules/nginx-lua/t/023-rewrite/request_body.t @@ -170,4 +170,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug - diff --git a/debian/modules/nginx-lua/t/023-rewrite/sanity.t b/debian/modules/nginx-lua/t/023-rewrite/sanity.t index 20b00e2..b90aa0e 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/sanity.t +++ b/debian/modules/nginx-lua/t/023-rewrite/sanity.t @@ -799,4 +799,3 @@ test test --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/sleep.t b/debian/modules/nginx-lua/t/023-rewrite/sleep.t index 1719784..8d4c2da 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/sleep.t +++ b/debian/modules/nginx-lua/t/023-rewrite/sleep.t @@ -219,4 +219,3 @@ hello world hello world --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t index 50de0b3..489a70f 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t +++ b/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t @@ -1007,4 +1007,3 @@ Not found, dear... --- error_code: 404 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t index a307388..5d1e8f0 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t +++ b/debian/modules/nginx-lua/t/023-rewrite/subrequest.t @@ -639,4 +639,3 @@ the nginx core requires the patch https://github.com/agentzh/ngx_openresty/blob/ GET /t --- response_body done - diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t index 79cd0b9..15bec7f 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t @@ -41,7 +41,7 @@ __DATA__ --- config server_tokens off; lua_socket_connect_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t1 { rewrite_by_lua ' @@ -73,7 +73,7 @@ lua tcp socket connect timed out server_tokens off; lua_socket_connect_timeout 60s; lua_socket_log_errors off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t2 { rewrite_by_lua ' @@ -108,7 +108,7 @@ lua tcp socket connect timeout: 150 server_tokens off; lua_socket_log_errors off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; #resolver_timeout 3s; location /t3 { rewrite_by_lua ' @@ -143,7 +143,7 @@ lua tcp socket connect timeout: 102 server_tokens off; lua_socket_connect_timeout 102ms; lua_socket_log_errors off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t4 { rewrite_by_lua ' @@ -179,7 +179,7 @@ lua tcp socket connect timeout: 102 server_tokens off; lua_socket_connect_timeout 102ms; lua_socket_log_errors off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t5 { rewrite_by_lua ' @@ -251,7 +251,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -292,7 +292,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -333,7 +333,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -375,7 +375,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -416,7 +416,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_send_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -455,7 +455,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -496,7 +496,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -537,7 +537,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -578,7 +578,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { rewrite_by_lua ' local sock = ngx.socket.tcp() @@ -612,4 +612,3 @@ failed to send: timeout lua tcp socket send timeout: 102 lua tcp socket connect timeout: 60000 lua tcp socket write timed out - diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t index cf9d80a..bff69a5 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t @@ -204,7 +204,7 @@ attempt to send data on a closed socket: --- timeout: 10 --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { rewrite_by_lua ' @@ -296,7 +296,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ === TEST 6: connection timeout (tcp) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_socket_connect_timeout 100ms; lua_socket_send_timeout 100ms; lua_socket_read_timeout 100ms; @@ -372,7 +372,7 @@ connected: 1 === TEST 8: resolver error (host not found) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { rewrite_by_lua ' @@ -415,7 +415,7 @@ attempt to send data on a closed socket === TEST 9: resolver error (timeout) --- config server_tokens off; - resolver 8.8.8.8; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 1ms; location /t { rewrite_by_lua ' @@ -2390,4 +2390,3 @@ qr/runtime error: rewrite_by_lua\(nginx\.conf:\d+\):16: bad request/ --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t b/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t index 098dd67..8a5f000 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t +++ b/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t @@ -150,4 +150,3 @@ received: received: foo failed to receive a line: closed close: 1 nil - diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t index 0f125e0..83de1a3 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t @@ -186,4 +186,3 @@ free request --- error_code: 302 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t index 58af7d0..5552107 100644 --- a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t @@ -1449,4 +1449,3 @@ status: 204 --- no_error_log [error] --- timeout: 3 - diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/nginx-lua/t/024-access/auth.t index 5da09cb..56e9862 100644 --- a/debian/modules/nginx-lua/t/024-access/auth.t +++ b/debian/modules/nginx-lua/t/024-access/auth.t @@ -107,4 +107,3 @@ Location: /terms_of_use\.html GET /lua --- response_body_like: 403 Forbidden --- error_code: 403 - diff --git a/debian/modules/nginx-lua/t/024-access/client-abort.t b/debian/modules/nginx-lua/t/024-access/client-abort.t index a94f822..c16f4ea 100644 --- a/debian/modules/nginx-lua/t/024-access/client-abort.t +++ b/debian/modules/nginx-lua/t/024-access/client-abort.t @@ -850,4 +850,3 @@ delete thread 1 --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/024-access/exit.t b/debian/modules/nginx-lua/t/024-access/exit.t index 8470ab9..d6d66b8 100644 --- a/debian/modules/nginx-lua/t/024-access/exit.t +++ b/debian/modules/nginx-lua/t/024-access/exit.t @@ -545,4 +545,3 @@ Not found, dear... --- response_body Not found, dear... --- error_code: 404 - diff --git a/debian/modules/nginx-lua/t/024-access/multi-capture.t b/debian/modules/nginx-lua/t/024-access/multi-capture.t index 368d401..930b74d 100644 --- a/debian/modules/nginx-lua/t/024-access/multi-capture.t +++ b/debian/modules/nginx-lua/t/024-access/multi-capture.t @@ -392,4 +392,3 @@ res4.status = 201 res4.body = STORED\r " - diff --git a/debian/modules/nginx-lua/t/024-access/on-abort.t b/debian/modules/nginx-lua/t/024-access/on-abort.t index 0c17b55..5bb948b 100644 --- a/debian/modules/nginx-lua/t/024-access/on-abort.t +++ b/debian/modules/nginx-lua/t/024-access/on-abort.t @@ -649,4 +649,3 @@ delete thread 2 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/nginx-lua/t/024-access/redirect.t index c7ce512..b45fac7 100644 --- a/debian/modules/nginx-lua/t/024-access/redirect.t +++ b/debian/modules/nginx-lua/t/024-access/redirect.t @@ -122,4 +122,3 @@ GET /read --- raw_response_headers_like: Location: /foo\r\n --- response_body_like: 302 Found --- error_code: 302 - diff --git a/debian/modules/nginx-lua/t/024-access/req-body.t b/debian/modules/nginx-lua/t/024-access/req-body.t index fd33aff..70db85c 100644 --- a/debian/modules/nginx-lua/t/024-access/req-body.t +++ b/debian/modules/nginx-lua/t/024-access/req-body.t @@ -218,4 +218,3 @@ hiya, world"] --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/024-access/request_body.t b/debian/modules/nginx-lua/t/024-access/request_body.t index a6fead2..fa03195 100644 --- a/debian/modules/nginx-lua/t/024-access/request_body.t +++ b/debian/modules/nginx-lua/t/024-access/request_body.t @@ -170,4 +170,3 @@ Expect: 100-Continue http finalize request: 500, "/echo_body?" a:1, c:2 http finalize request: 500, "/echo_body?" a:1, c:0 --- log_level: debug - diff --git a/debian/modules/nginx-lua/t/024-access/sanity.t b/debian/modules/nginx-lua/t/024-access/sanity.t index de63a68..7ff177f 100644 --- a/debian/modules/nginx-lua/t/024-access/sanity.t +++ b/debian/modules/nginx-lua/t/024-access/sanity.t @@ -741,4 +741,3 @@ test test --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/024-access/satisfy.t b/debian/modules/nginx-lua/t/024-access/satisfy.t index 10d3ece..7902f49 100644 --- a/debian/modules/nginx-lua/t/024-access/satisfy.t +++ b/debian/modules/nginx-lua/t/024-access/satisfy.t @@ -209,4 +209,3 @@ something important --- error_code: 200 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/sleep.t b/debian/modules/nginx-lua/t/024-access/sleep.t index 2eb0822..fc1fc02 100644 --- a/debian/modules/nginx-lua/t/024-access/sleep.t +++ b/debian/modules/nginx-lua/t/024-access/sleep.t @@ -219,4 +219,3 @@ hello world hello world --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/subrequest.t b/debian/modules/nginx-lua/t/024-access/subrequest.t index bfe96d6..b6ccf11 100644 --- a/debian/modules/nginx-lua/t/024-access/subrequest.t +++ b/debian/modules/nginx-lua/t/024-access/subrequest.t @@ -599,4 +599,3 @@ the nginx core requires the patch https://github.com/agentzh/ngx_openresty/blob/ GET /t --- response_body done - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exec.t b/debian/modules/nginx-lua/t/024-access/uthread-exec.t index d7c2321..7add3d4 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exec.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exec.t @@ -344,4 +344,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exit.t b/debian/modules/nginx-lua/t/024-access/uthread-exit.t index da4a9db..7c146ae 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-exit.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-exit.t @@ -1311,4 +1311,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t index 8b030ac..4eb4759 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-redirect.t @@ -187,4 +187,3 @@ free request --- error_code: 302 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t index 415e4c0..7c7ba3b 100644 --- a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t +++ b/debian/modules/nginx-lua/t/024-access/uthread-spawn.t @@ -1116,4 +1116,3 @@ body: hello world)$ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/025-codecache.t b/debian/modules/nginx-lua/t/025-codecache.t index f33452a..0b02a27 100644 --- a/debian/modules/nginx-lua/t/025-codecache.t +++ b/debian/modules/nginx-lua/t/025-codecache.t @@ -1244,4 +1244,3 @@ qr/\[alert\] \S+ lua_code_cache is off; this will hurt performance/, "decrementing the reference count for Lua VM: 1", "lua close the global Lua VM", ] - diff --git a/debian/modules/nginx-lua/t/026-mysql.t b/debian/modules/nginx-lua/t/026-mysql.t index e14ffb6..569f96f 100644 --- a/debian/modules/nginx-lua/t/026-mysql.t +++ b/debian/modules/nginx-lua/t/026-mysql.t @@ -66,7 +66,7 @@ __DATA__ ^status = 504 thread id = \d+ kill status = 200 -kill body = {"errcode":0}$ +kill body = \{"errcode":0\}$ --- error_log eval qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizzle upstream} @@ -126,6 +126,5 @@ qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizz ^status = 504 thread id = \d+ kill status = 200 -kill body = {"errcode":0}$ +kill body = \{"errcode":0\}$ --- SKIP - diff --git a/debian/modules/nginx-lua/t/027-multi-capture.t b/debian/modules/nginx-lua/t/027-multi-capture.t index 3588c69..9227fe5 100644 --- a/debian/modules/nginx-lua/t/027-multi-capture.t +++ b/debian/modules/nginx-lua/t/027-multi-capture.t @@ -752,4 +752,3 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz GET /foo --- response_body ok - diff --git a/debian/modules/nginx-lua/t/029-http-time.t b/debian/modules/nginx-lua/t/029-http-time.t index 71a7758..ecef492 100644 --- a/debian/modules/nginx-lua/t/029-http-time.t +++ b/debian/modules/nginx-lua/t/029-http-time.t @@ -85,4 +85,3 @@ GET /lua GET /lua --- response_body nil - diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/nginx-lua/t/030-uri-args.t index 8ee8401..96e216c 100644 --- a/debian/modules/nginx-lua/t/030-uri-args.t +++ b/debian/modules/nginx-lua/t/030-uri-args.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 17); +plan tests => repeat_each() * (blocks() * 2 + 18); no_root_location(); @@ -1390,3 +1390,19 @@ GET /lua --- response_body_like ^HTTP/1.0 (a=3&b|b&a=3)$ + + +=== TEST 57: ngx.encode_args (escaping) +--- config + location /lua { + content_by_lua_block { + local t = {bar = "-_.!~*'()", foo = ",$@|`"} + ngx.say("args: ", ngx.encode_args(t)) + } + } +--- request +GET /lua +--- response_body +args: foo=%2C%24%40%7C%60&bar=-_.!~*'() +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/nginx-lua/t/031-post-args.t index c2b6b8f..62c88c1 100644 --- a/debian/modules/nginx-lua/t/031-post-args.t +++ b/debian/modules/nginx-lua/t/031-post-args.t @@ -351,6 +351,6 @@ CORE::join("", @k); POST /lua a=3&b=4&c --- response_body -requesty body in temp file not supported +request body in temp file not supported --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/032-iolist.t b/debian/modules/nginx-lua/t/032-iolist.t index ddf3d7f..3c56032 100644 --- a/debian/modules/nginx-lua/t/032-iolist.t +++ b/debian/modules/nginx-lua/t/032-iolist.t @@ -76,4 +76,3 @@ GET /lua GET /lua --- response_body_like: 500 Internal Server Error --- error_code: 500 - diff --git a/debian/modules/nginx-lua/t/033-ctx.t b/debian/modules/nginx-lua/t/033-ctx.t index eefb216..8fc50aa 100644 --- a/debian/modules/nginx-lua/t/033-ctx.t +++ b/debian/modules/nginx-lua/t/033-ctx.t @@ -440,4 +440,3 @@ lua release ngx.ctx at ref --- response_body --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/034-match.t b/debian/modules/nginx-lua/t/034-match.t index 35149f1..ebe5762 100644 --- a/debian/modules/nginx-lua/t/034-match.t +++ b/debian/modules/nginx-lua/t/034-match.t @@ -1017,7 +1017,7 @@ exec opts: 0 === TEST 45: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -1057,7 +1057,7 @@ error: pcre_exec() failed: -8 === TEST 46: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; diff --git a/debian/modules/nginx-lua/t/035-gmatch.t b/debian/modules/nginx-lua/t/035-gmatch.t index 69b9512..5b63ae4 100644 --- a/debian/modules/nginx-lua/t/035-gmatch.t +++ b/debian/modules/nginx-lua/t/035-gmatch.t @@ -814,7 +814,7 @@ exec opts: 0 === TEST 30: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -860,7 +860,7 @@ error: pcre_exec() failed: -8 === TEST 31: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; @@ -901,4 +901,3 @@ end GET /re --- response_body failed to match - diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/nginx-lua/t/036-sub.t index f08c50f..2b4b075 100644 --- a/debian/modules/nginx-lua/t/036-sub.t +++ b/debian/modules/nginx-lua/t/036-sub.t @@ -580,7 +580,7 @@ s: a好 === TEST 28: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -617,7 +617,7 @@ error: pcre_exec() failed: -8 === TEST 29: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/nginx-lua/t/037-gsub.t index 2a1e00f..4c5810d 100644 --- a/debian/modules/nginx-lua/t/037-gsub.t +++ b/debian/modules/nginx-lua/t/037-gsub.t @@ -501,7 +501,7 @@ s: aa === TEST 23: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -538,7 +538,7 @@ error: pcre_exec() failed: -8 === TEST 24: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; diff --git a/debian/modules/nginx-lua/t/038-match-o.t b/debian/modules/nginx-lua/t/038-match-o.t index 628e27f..d61ff1f 100644 --- a/debian/modules/nginx-lua/t/038-match-o.t +++ b/debian/modules/nginx-lua/t/038-match-o.t @@ -740,4 +740,3 @@ false hello false false - diff --git a/debian/modules/nginx-lua/t/039-sub-o.t b/debian/modules/nginx-lua/t/039-sub-o.t index a861b6c..580a671 100644 --- a/debian/modules/nginx-lua/t/039-sub-o.t +++ b/debian/modules/nginx-lua/t/039-sub-o.t @@ -578,4 +578,3 @@ a [b c] [b] [c] [] [] d --- response_body a [b c] [b] [c] d 1 - diff --git a/debian/modules/nginx-lua/t/040-gsub-o.t b/debian/modules/nginx-lua/t/040-gsub-o.t index 90619b0..5347266 100644 --- a/debian/modules/nginx-lua/t/040-gsub-o.t +++ b/debian/modules/nginx-lua/t/040-gsub-o.t @@ -198,4 +198,3 @@ hello, world --- response_body [hello,h], [world,w] 2 - diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/nginx-lua/t/041-header-filter.t index 553ee43..9cca3b7 100644 --- a/debian/modules/nginx-lua/t/041-header-filter.t +++ b/debian/modules/nginx-lua/t/041-header-filter.t @@ -790,4 +790,3 @@ GET /t --- error_code: 302 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/042-crc32.t b/debian/modules/nginx-lua/t/042-crc32.t index 86d9201..73aa1f4 100644 --- a/debian/modules/nginx-lua/t/042-crc32.t +++ b/debian/modules/nginx-lua/t/042-crc32.t @@ -54,4 +54,3 @@ GET /test GET /test --- response_body 0 - diff --git a/debian/modules/nginx-lua/t/045-ngx-var.t b/debian/modules/nginx-lua/t/045-ngx-var.t index 8f2dcb3..6475f1e 100644 --- a/debian/modules/nginx-lua/t/045-ngx-var.t +++ b/debian/modules/nginx-lua/t/045-ngx-var.t @@ -154,14 +154,15 @@ invalid referer: 1 -=== TEST 8: $proxy_host & $proxy_port +=== TEST 8: $proxy_host & $proxy_port & $proxy_add_x_forwarded_for --- config location = /t { proxy_pass http://127.0.0.1:$server_port/back; - header_filter_by_lua ' + header_filter_by_lua_block { ngx.header["Proxy-Host"] = ngx.var.proxy_host ngx.header["Proxy-Port"] = ngx.var.proxy_port - '; + ngx.header["Proxy-Add-X-Forwarded-For"] = ngx.var.proxy_add_x_forwarded_for + } } location = /back { @@ -172,6 +173,7 @@ GET /t --- raw_response_headers_like Proxy-Host: 127.0.0.1\:\d+\r Proxy-Port: \d+\r +Proxy-Add-X-Forwarded-For: 127.0.0.1\r --- response_body hello --- no_error_log @@ -226,4 +228,3 @@ GET /test?hello --- error_log variable "query_string" not changeable --- error_code: 500 - diff --git a/debian/modules/nginx-lua/t/046-hmac.t b/debian/modules/nginx-lua/t/046-hmac.t index 686b479..32e222b 100644 --- a/debian/modules/nginx-lua/t/046-hmac.t +++ b/debian/modules/nginx-lua/t/046-hmac.t @@ -29,4 +29,3 @@ __DATA__ GET /lua --- response_body R/pvxzHC4NLtj7S+kXFg/NePTmk= - diff --git a/debian/modules/nginx-lua/t/047-match-jit.t b/debian/modules/nginx-lua/t/047-match-jit.t index 077ebb6..2417a63 100644 --- a/debian/modules/nginx-lua/t/047-match-jit.t +++ b/debian/modules/nginx-lua/t/047-match-jit.t @@ -212,4 +212,3 @@ end GET /re --- response_body failed to match - diff --git a/debian/modules/nginx-lua/t/048-match-dfa.t b/debian/modules/nginx-lua/t/048-match-dfa.t index 8a0a328..28b5a60 100644 --- a/debian/modules/nginx-lua/t/048-match-dfa.t +++ b/debian/modules/nginx-lua/t/048-match-dfa.t @@ -207,4 +207,3 @@ exec opts: 0 你 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/049-gmatch-jit.t b/debian/modules/nginx-lua/t/049-gmatch-jit.t index 614c440..5134d52 100644 --- a/debian/modules/nginx-lua/t/049-gmatch-jit.t +++ b/debian/modules/nginx-lua/t/049-gmatch-jit.t @@ -226,4 +226,3 @@ qr/pcre JIT compiling result: \d+/ error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/051-sub-jit.t b/debian/modules/nginx-lua/t/051-sub-jit.t index 789e897..c8a49c0 100644 --- a/debian/modules/nginx-lua/t/051-sub-jit.t +++ b/debian/modules/nginx-lua/t/051-sub-jit.t @@ -147,4 +147,3 @@ error: pcre_compile() failed: missing ) in "(abc" error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/053-gsub-jit.t b/debian/modules/nginx-lua/t/053-gsub-jit.t index 3a2a1aa..3efc0a2 100644 --- a/debian/modules/nginx-lua/t/053-gsub-jit.t +++ b/debian/modules/nginx-lua/t/053-gsub-jit.t @@ -147,4 +147,3 @@ error: pcre_compile() failed: missing ) in "(abc" error: pcre_compile() failed: missing ) in "(abc" --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/055-subreq-vars.t b/debian/modules/nginx-lua/t/055-subreq-vars.t index 2fc6960..eb5e24d 100644 --- a/debian/modules/nginx-lua/t/055-subreq-vars.t +++ b/debian/modules/nginx-lua/t/055-subreq-vars.t @@ -336,4 +336,3 @@ dog = hiya cat = 56 parent dog: blah parent cat: foo - diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/nginx-lua/t/056-flush.t index d189cd5..6b697a4 100644 --- a/debian/modules/nginx-lua/t/056-flush.t +++ b/debian/modules/nginx-lua/t/056-flush.t @@ -520,4 +520,3 @@ qr/lua flush requires waiting: buffered 0x[0-9a-f]+, delayed:1/, --- no_error_log [error] --- timeout: 4 - diff --git a/debian/modules/nginx-lua/t/057-flush-timeout.t b/debian/modules/nginx-lua/t/057-flush-timeout.t index d6e0f86..a046539 100644 --- a/debian/modules/nginx-lua/t/057-flush-timeout.t +++ b/debian/modules/nginx-lua/t/057-flush-timeout.t @@ -318,4 +318,3 @@ qr/failed to flush: client aborted/, --- timeout: 0.2 --- abort --- wait: 1 - diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/nginx-lua/t/058-tcp-socket.t index acf69f0..1ee113b 100644 --- a/debian/modules/nginx-lua/t/058-tcp-socket.t +++ b/debian/modules/nginx-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 187; +plan tests => repeat_each() * 190; our $HtmlDir = html_dir; @@ -200,7 +200,7 @@ attempt to send data on a closed socket: --- timeout: 10 --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -290,7 +290,7 @@ qr/connect\(\) failed \(\d+: Connection refused\)/ === TEST 6: connection timeout (tcp) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_socket_connect_timeout 100ms; lua_socket_send_timeout 100ms; lua_socket_read_timeout 100ms; @@ -362,7 +362,7 @@ connected: 1 === TEST 8: resolver error (host not found) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -403,7 +403,7 @@ attempt to send data on a closed socket === TEST 9: resolver error (timeout) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 1ms; location /t { content_by_lua ' @@ -1995,7 +1995,7 @@ close: 1 nil === TEST 33: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location = /sub { content_by_lua ' @@ -2038,7 +2038,7 @@ resolve name done === TEST 34: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 5s; location = /sub { @@ -2136,7 +2136,7 @@ close: nil closed --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2178,7 +2178,7 @@ lua tcp socket read timed out === TEST 37: successful reread after a read time out happen (receive -> receive) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2255,7 +2255,7 @@ lua tcp socket read timed out === TEST 38: successful reread after a read time out happen (receive -> receiveuntil) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2335,7 +2335,7 @@ lua tcp socket read timed out === TEST 39: successful reread after a read time out happen (receiveuntil -> receiveuntil) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -2417,7 +2417,7 @@ lua tcp socket read timed out === TEST 40: successful reread after a read time out happen (receiveuntil -> receive) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -3015,7 +3015,7 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):16: bad request/ === TEST 50: cosocket resolving aborted by coroutine yielding failures (require) --- http_config lua_package_path "$prefix/html/?.lua;;"; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; --- config location = /t { @@ -3049,7 +3049,7 @@ runtime error: attempt to yield across C-call boundary === TEST 51: cosocket resolving aborted by coroutine yielding failures (xpcall err) --- http_config lua_package_path "$prefix/html/?.lua;;"; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; --- config location = /t { @@ -3307,7 +3307,7 @@ close: 1 nil --- config server_tokens off; lua_socket_connect_timeout 1s; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -3640,3 +3640,53 @@ failed to receive a line: closed [] close: 1 nil --- error_log lua http cleanup reuse + + + +=== TEST 60: options_table is nil +--- config + location /t { + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua_block { + local sock = ngx.socket.tcp() + local port = ngx.var.port + + local ok, err = sock:connect("127.0.0.1", port, nil) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local req = "flush_all\r\n" + + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send request: ", err) + return + end + ngx.say("request sent: ", bytes) + + local line, err, part = sock:receive() + if line then + ngx.say("received: ", line) + + else + ngx.say("failed to receive a line: ", err, " [", part, "]") + end + + ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + } + } +--- request +GET /t +--- response_body +connected: 1 +request sent: 11 +received: OK +close: 1 nil +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/060-lua-memcached.t b/debian/modules/nginx-lua/t/060-lua-memcached.t index e1ebb92..0751238 100644 --- a/debian/modules/nginx-lua/t/060-lua-memcached.t +++ b/debian/modules/nginx-lua/t/060-lua-memcached.t @@ -166,4 +166,3 @@ some_key: hello 1234 [error] --- error_log lua reuse free buf memory - diff --git a/debian/modules/nginx-lua/t/061-lua-redis.t b/debian/modules/nginx-lua/t/061-lua-redis.t index d7b1876..ebfa6d1 100644 --- a/debian/modules/nginx-lua/t/061-lua-redis.t +++ b/debian/modules/nginx-lua/t/061-lua-redis.t @@ -182,4 +182,3 @@ abort: function msg type: nil --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/nginx-lua/t/062-count.t index c3973ad..a69c33e 100644 --- a/debian/modules/nginx-lua/t/062-count.t +++ b/debian/modules/nginx-lua/t/062-count.t @@ -323,7 +323,7 @@ ngx. entry count: 116 --- request GET /test --- response_body -n = 3 +n = 4 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/063-abort.t b/debian/modules/nginx-lua/t/063-abort.t index c112ee1..411a07e 100644 --- a/debian/modules/nginx-lua/t/063-abort.t +++ b/debian/modules/nginx-lua/t/063-abort.t @@ -1017,4 +1017,3 @@ foo --- no_error_log [error] --- timeout: 2 - diff --git a/debian/modules/nginx-lua/t/064-pcall.t b/debian/modules/nginx-lua/t/064-pcall.t index cf90a07..3011f3e 100644 --- a/debian/modules/nginx-lua/t/064-pcall.t +++ b/debian/modules/nginx-lua/t/064-pcall.t @@ -104,4 +104,3 @@ $/ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t b/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t index ec79891..212766e 100644 --- a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t @@ -46,7 +46,7 @@ __DATA__ --- config server_tokens off; lua_socket_connect_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -75,7 +75,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 60s; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -105,7 +105,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -133,7 +133,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -163,7 +163,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_connect_timeout 102ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -191,7 +191,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -228,7 +228,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -267,7 +267,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -306,7 +306,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -346,7 +346,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_read_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -385,7 +385,7 @@ lua tcp socket read timed out --- config server_tokens off; lua_socket_send_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -436,7 +436,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 60s; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -475,7 +475,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -514,7 +514,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -553,7 +553,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_send_timeout 102ms; - #resolver $TEST_NGINX_RESOLVER; + #resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -686,7 +686,7 @@ after --- config server_tokens off; lua_socket_connect_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /t { content_by_lua ' @@ -724,7 +724,7 @@ lua tcp socket connect timed out --- config server_tokens off; lua_socket_send_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -779,7 +779,7 @@ lua tcp socket write timed out === TEST 19: abort when upstream sockets pending on writes --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -832,7 +832,7 @@ lua tcp socket write timed out === TEST 20: abort when downstream socket pending on writes --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' ngx.send_headers() @@ -888,7 +888,7 @@ lua tcp socket write timed out --- config server_tokens off; lua_socket_read_timeout 100ms; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { content_by_lua ' local sock = ngx.socket.tcp() @@ -994,4 +994,3 @@ close: 1 nil --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t b/debian/modules/nginx-lua/t/066-socket-receiveuntil.t index 3bf5229..ffe74aa 100644 --- a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t +++ b/debian/modules/nginx-lua/t/066-socket-receiveuntil.t @@ -1329,4 +1329,3 @@ this exposed a memory leak in receiveuntil ok --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/067-req-socket.t b/debian/modules/nginx-lua/t/067-req-socket.t index 30a653a..229d5cc 100644 --- a/debian/modules/nginx-lua/t/067-req-socket.t +++ b/debian/modules/nginx-lua/t/067-req-socket.t @@ -1096,4 +1096,3 @@ done --- grep_error_log_out lua finalize socket GC cycle done - diff --git a/debian/modules/nginx-lua/t/069-null.t b/debian/modules/nginx-lua/t/069-null.t index 7761c91..e4c26af 100644 --- a/debian/modules/nginx-lua/t/069-null.t +++ b/debian/modules/nginx-lua/t/069-null.t @@ -93,4 +93,3 @@ done ngx.null: null --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/071-idle-socket.t b/debian/modules/nginx-lua/t/071-idle-socket.t index 55d25c6..c9002be 100644 --- a/debian/modules/nginx-lua/t/071-idle-socket.t +++ b/debian/modules/nginx-lua/t/071-idle-socket.t @@ -431,4 +431,3 @@ failed to set keepalive: unread data in buffer } --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/072-conditional-get.t b/debian/modules/nginx-lua/t/072-conditional-get.t index 4bb567a..7cf2dcd 100644 --- a/debian/modules/nginx-lua/t/072-conditional-get.t +++ b/debian/modules/nginx-lua/t/072-conditional-get.t @@ -88,4 +88,3 @@ delete thread 1 say failed: nginx output filter error --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/073-backtrace.t b/debian/modules/nginx-lua/t/073-backtrace.t index aae4bae..6c54692 100644 --- a/debian/modules/nginx-lua/t/073-backtrace.t +++ b/debian/modules/nginx-lua/t/073-backtrace.t @@ -187,4 +187,3 @@ probe process("$LIBLUA_PATH").function("lua_concat") { :79: in function 'func20' :83: in function 'func21' ... - diff --git a/debian/modules/nginx-lua/t/074-prefix-var.t b/debian/modules/nginx-lua/t/074-prefix-var.t index 3cc4587..c116d84 100644 --- a/debian/modules/nginx-lua/t/074-prefix-var.t +++ b/debian/modules/nginx-lua/t/074-prefix-var.t @@ -64,4 +64,3 @@ GET /t Greetings from module foo. --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/075-logby.t b/debian/modules/nginx-lua/t/075-logby.t index f987c8e..520c62e 100644 --- a/debian/modules/nginx-lua/t/075-logby.t +++ b/debian/modules/nginx-lua/t/075-logby.t @@ -581,4 +581,3 @@ qr{log_by_lua\(nginx\.conf:\d+\):1: content-type: text/plain} --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/077-sleep.t b/debian/modules/nginx-lua/t/077-sleep.t index a7c251a..96f04bd 100644 --- a/debian/modules/nginx-lua/t/077-sleep.t +++ b/debian/modules/nginx-lua/t/077-sleep.t @@ -9,10 +9,10 @@ log_level('debug'); repeat_each(2); -plan tests => repeat_each() * 63; +plan tests => repeat_each() * 71; #no_diff(); -#no_long_string(); +no_long_string(); run_tests(); __DATA__ @@ -405,3 +405,98 @@ ok [error] [alert] + + +=== TEST 16: sleep 0 +--- config + location /t { + content_by_lua_block { + local function f (n) + print("f begin ", n) + ngx.sleep(0) + print("f middle ", n) + ngx.sleep(0) + print("f end ", n) + ngx.sleep(0) + end + + for i = 1, 3 do + assert(ngx.thread.spawn(f, i)) + end + + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/\bf (?:begin|middle|end)\b|\bworker cycle$|\be?poll timer: \d+$/ +--- grep_error_log_out eval +qr/f begin +f begin +f begin +worker cycle +e?poll timer: 0 +f middle +f middle +f middle +worker cycle +e?poll timer: 0 +f end +f end +f end +worker cycle +e?poll timer: 0 +/ + + + +=== TEST 17: sleep short times less than 1ms +--- config + location /t { + content_by_lua_block { + local delay = 0.0005 + + local function f (n) + print("f begin ", n) + ngx.sleep(delay) + print("f middle ", n) + ngx.sleep(delay) + print("f end ", n) + ngx.sleep(delay) + end + + for i = 1, 3 do + assert(ngx.thread.spawn(f, i)) + end + + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +ok +--- no_error_log +[error] +--- grep_error_log eval: qr/\bf (?:begin|middle|end)\b|\bworker cycle$|\be?poll timer: \d+$/ +--- grep_error_log_out eval +qr/f begin +f begin +f begin +worker cycle +e?poll timer: 0 +f middle +f middle +f middle +worker cycle +e?poll timer: 0 +f end +f end +f end +worker cycle +e?poll timer: 0 +/ diff --git a/debian/modules/nginx-lua/t/078-hup-vars.t b/debian/modules/nginx-lua/t/078-hup-vars.t index 8acc346..5072c4d 100644 --- a/debian/modules/nginx-lua/t/078-hup-vars.t +++ b/debian/modules/nginx-lua/t/078-hup-vars.t @@ -62,4 +62,3 @@ GET /t localhost --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/079-unused-directives.t b/debian/modules/nginx-lua/t/079-unused-directives.t index cba0e41..aacd0d3 100644 --- a/debian/modules/nginx-lua/t/079-unused-directives.t +++ b/debian/modules/nginx-lua/t/079-unused-directives.t @@ -340,4 +340,3 @@ GET /t sub: sub --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/080-hup-shdict.t b/debian/modules/nginx-lua/t/080-hup-shdict.t index f9a0278..c762556 100644 --- a/debian/modules/nginx-lua/t/080-hup-shdict.t +++ b/debian/modules/nginx-lua/t/080-hup-shdict.t @@ -82,4 +82,3 @@ GET /test 10502 number --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/083-bad-sock-self.t b/debian/modules/nginx-lua/t/083-bad-sock-self.t index b93849f..7a76752 100644 --- a/debian/modules/nginx-lua/t/083-bad-sock-self.t +++ b/debian/modules/nginx-lua/t/083-bad-sock-self.t @@ -136,4 +136,3 @@ bad argument #1 to 'close' (table expected, got number) --- error_code: 500 --- error_log bad argument #1 to 'setkeepalive' (table expected, got number) - diff --git a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t b/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t index c966015..f7d5d3d 100644 --- a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t +++ b/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t @@ -743,4 +743,3 @@ close: 1 nil } --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/085-if.t b/debian/modules/nginx-lua/t/085-if.t index e08b43c..33f57ca 100644 --- a/debian/modules/nginx-lua/t/085-if.t +++ b/debian/modules/nginx-lua/t/085-if.t @@ -198,4 +198,3 @@ GET /proxy-pass-uri --- response_body_like: It works! --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/086-init-by.t b/debian/modules/nginx-lua/t/086-init-by.t index 3a474fe..bea34a4 100644 --- a/debian/modules/nginx-lua/t/086-init-by.t +++ b/debian/modules/nginx-lua/t/086-init-by.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 3 + 3); +plan tests => repeat_each() * (blocks() * 3 + 2); #no_diff(); #no_long_string(); @@ -304,3 +304,20 @@ INIT 2: foo = 3 ", "", ] + + + +=== TEST 12: error in init +--- http_config + init_by_lua_block { + error("failed to init") + } +--- config + location /t { + echo ok; + } +--- must_die +--- error_log +failed to init +--- error_log +[error] diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/nginx-lua/t/087-udp-socket.t index 79ba452..a847031 100644 --- a/debian/modules/nginx-lua/t/087-udp-socket.t +++ b/debian/modules/nginx-lua/t/087-udp-socket.t @@ -596,6 +596,7 @@ received a good response. --- log_level: debug --- error_log lua udp socket receive buffer size: 8192 +--- no_check_leak @@ -662,12 +663,14 @@ received a good response. --- log_level: debug --- error_log lua udp socket receive buffer size: 8192 +--- no_check_leak === TEST 12: github issue #215: Handle the posted requests in lua cosocket api (failed to resolve) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; + resolver_timeout 5s; location = /sub { content_by_lua ' @@ -704,12 +707,13 @@ resolve name done --- no_error_log [error] +--- timeout: 10 === TEST 13: github issue #215: Handle the posted requests in lua cosocket api (successfully resolved) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 5s; location = /sub { @@ -1100,4 +1104,3 @@ qr/runtime error: content_by_lua\(nginx\.conf:\d+\):14: bad request/ --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/088-req-method.t b/debian/modules/nginx-lua/t/088-req-method.t index 9ced40c..198b3b3 100644 --- a/debian/modules/nginx-lua/t/088-req-method.t +++ b/debian/modules/nginx-lua/t/088-req-method.t @@ -262,4 +262,3 @@ method: PATCH method: TRACE --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/089-phase.t b/debian/modules/nginx-lua/t/089-phase.t index 57921fc..94b7619 100644 --- a/debian/modules/nginx-lua/t/089-phase.t +++ b/debian/modules/nginx-lua/t/089-phase.t @@ -176,4 +176,3 @@ GET /lua init_worker --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/090-log-socket-errors.t b/debian/modules/nginx-lua/t/090-log-socket-errors.t index a5943c2..8e498cd 100644 --- a/debian/modules/nginx-lua/t/090-log-socket-errors.t +++ b/debian/modules/nginx-lua/t/090-log-socket-errors.t @@ -11,6 +11,8 @@ repeat_each(2); plan tests => repeat_each() * (blocks() * 3); +$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; + #no_diff(); #no_long_string(); run_tests(); @@ -19,12 +21,14 @@ __DATA__ === TEST 1: log socket errors off (tcp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_connect_timeout 1ms; lua_socket_log_errors off; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("8.8.8.8", 80) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -39,12 +43,14 @@ timeout === TEST 2: log socket errors on (tcp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_connect_timeout 1ms; lua_socket_log_errors on; content_by_lua ' local sock = ngx.socket.tcp() - local ok, err = sock:connect("8.8.8.8", 80) + local ok, err = sock:connect("agentzh.org", 12345) ngx.say(err) '; } @@ -59,12 +65,14 @@ lua tcp socket connect timed out === TEST 3: log socket errors on (udp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_log_errors on; lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("8.8.8.8", 80) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -80,12 +88,14 @@ lua udp socket read timed out === TEST 4: log socket errors off (udp) --- config + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { lua_socket_log_errors off; lua_socket_read_timeout 1ms; content_by_lua ' local sock = ngx.socket.udp() - local ok, err = sock:setpeername("8.8.8.8", 80) + local ok, err = sock:setpeername("agentzh.org", 12345) ok, err = sock:receive() ngx.say(err) '; @@ -96,4 +106,3 @@ GET /t timeout --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/091-coroutine.t b/debian/modules/nginx-lua/t/091-coroutine.t index b047ccb..bceb512 100644 --- a/debian/modules/nginx-lua/t/091-coroutine.t +++ b/debian/modules/nginx-lua/t/091-coroutine.t @@ -160,7 +160,7 @@ cc3: 2 === TEST 3: basic coroutine and cosocket --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -359,7 +359,7 @@ GET /lua === TEST 7: coroutine wrap and cosocket --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -987,7 +987,7 @@ test10 --- http_config init_by_lua 'return'; --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -1041,7 +1041,7 @@ successfully connected to: agentzh.org init_by_lua_file html/init.lua; --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' function worker(url) @@ -1315,4 +1315,3 @@ co yield: 2 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/092-eof.t b/debian/modules/nginx-lua/t/092-eof.t index a75711f..86778de 100644 --- a/debian/modules/nginx-lua/t/092-eof.t +++ b/debian/modules/nginx-lua/t/092-eof.t @@ -80,4 +80,3 @@ GET /t --- error_log hello, tom hello, jim - diff --git a/debian/modules/nginx-lua/t/093-uthread-spawn.t b/debian/modules/nginx-lua/t/093-uthread-spawn.t index 772e866..b622d30 100644 --- a/debian/modules/nginx-lua/t/093-uthread-spawn.t +++ b/debian/modules/nginx-lua/t/093-uthread-spawn.t @@ -1672,4 +1672,3 @@ delete thread 2 f --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/094-uthread-exit.t b/debian/modules/nginx-lua/t/094-uthread-exit.t index cd678c0..a623773 100644 --- a/debian/modules/nginx-lua/t/094-uthread-exit.t +++ b/debian/modules/nginx-lua/t/094-uthread-exit.t @@ -1648,4 +1648,3 @@ free request [alert] [error] [warn] - diff --git a/debian/modules/nginx-lua/t/095-uthread-exec.t b/debian/modules/nginx-lua/t/095-uthread-exec.t index 4459360..56156c4 100644 --- a/debian/modules/nginx-lua/t/095-uthread-exec.t +++ b/debian/modules/nginx-lua/t/095-uthread-exec.t @@ -423,4 +423,3 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] - diff --git a/debian/modules/nginx-lua/t/096-uthread-redirect.t b/debian/modules/nginx-lua/t/096-uthread-redirect.t index b0258fb..003c642 100644 --- a/debian/modules/nginx-lua/t/096-uthread-redirect.t +++ b/debian/modules/nginx-lua/t/096-uthread-redirect.t @@ -277,4 +277,3 @@ attempt to abort with pending subrequests --- no_error_log [alert] [warn] - diff --git a/debian/modules/nginx-lua/t/097-uthread-rewrite.t b/debian/modules/nginx-lua/t/097-uthread-rewrite.t index 178a374..a93adc8 100644 --- a/debian/modules/nginx-lua/t/097-uthread-rewrite.t +++ b/debian/modules/nginx-lua/t/097-uthread-rewrite.t @@ -344,4 +344,3 @@ free request end --- error_log attempt to abort with pending subrequests - diff --git a/debian/modules/nginx-lua/t/098-uthread-wait.t b/debian/modules/nginx-lua/t/098-uthread-wait.t index aaf020a..4948596 100644 --- a/debian/modules/nginx-lua/t/098-uthread-wait.t +++ b/debian/modules/nginx-lua/t/098-uthread-wait.t @@ -1321,4 +1321,3 @@ $s; --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/100-client-abort.t b/debian/modules/nginx-lua/t/100-client-abort.t index cd46859..89c1f6a 100644 --- a/debian/modules/nginx-lua/t/100-client-abort.t +++ b/debian/modules/nginx-lua/t/100-client-abort.t @@ -1064,4 +1064,3 @@ GET /t eof succeeded --- error_log eof failed: nginx output filter error - diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/nginx-lua/t/101-on-abort.t index 81cec78..182d12c 100644 --- a/debian/modules/nginx-lua/t/101-on-abort.t +++ b/debian/modules/nginx-lua/t/101-on-abort.t @@ -846,4 +846,3 @@ done client prematurely closed connection on abort called main handler done - diff --git a/debian/modules/nginx-lua/t/102-req-start-time.t b/debian/modules/nginx-lua/t/102-req-start-time.t index 1d5fe28..3b041af 100644 --- a/debian/modules/nginx-lua/t/102-req-start-time.t +++ b/debian/modules/nginx-lua/t/102-req-start-time.t @@ -113,4 +113,3 @@ true$ --- no_error_log [error] --- SKIP - diff --git a/debian/modules/nginx-lua/t/103-req-http-ver.t b/debian/modules/nginx-lua/t/103-req-http-ver.t index 6ded75a..e6de238 100644 --- a/debian/modules/nginx-lua/t/103-req-http-ver.t +++ b/debian/modules/nginx-lua/t/103-req-http-ver.t @@ -46,4 +46,3 @@ GET /t HTTP/1.0 1 --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/104-req-raw-header.t b/debian/modules/nginx-lua/t/104-req-raw-header.t index 439b9de..efea03c 100644 --- a/debian/modules/nginx-lua/t/104-req-raw-header.t +++ b/debian/modules/nginx-lua/t/104-req-raw-header.t @@ -876,4 +876,3 @@ Foo: bar\r --- no_error_log [error] --- timeout: 5 - diff --git a/debian/modules/nginx-lua/t/105-pressure.t b/debian/modules/nginx-lua/t/105-pressure.t index 10f495e..9d1ba1f 100644 --- a/debian/modules/nginx-lua/t/105-pressure.t +++ b/debian/modules/nginx-lua/t/105-pressure.t @@ -51,4 +51,3 @@ $::Id = int rand 10000; --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/nginx-lua/t/106-timer.t index d0f6f36..04a532e 100644 --- a/debian/modules/nginx-lua/t/106-timer.t +++ b/debian/modules/nginx-lua/t/106-timer.t @@ -2193,4 +2193,3 @@ ok --- error_log Bad bad bad --- skip_nginx: 4: < 1.7.1 - diff --git a/debian/modules/nginx-lua/t/107-timer-errors.t b/debian/modules/nginx-lua/t/107-timer-errors.t index 9ed1334..3201612 100644 --- a/debian/modules/nginx-lua/t/107-timer-errors.t +++ b/debian/modules/nginx-lua/t/107-timer-errors.t @@ -1420,4 +1420,3 @@ qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf:\d+\):3: API disable "lua ngx.timer expired", "http lua close fake http connection" ] - diff --git a/debian/modules/nginx-lua/t/108-timer-safe.t b/debian/modules/nginx-lua/t/108-timer-safe.t index 19c9f6d..2795998 100644 --- a/debian/modules/nginx-lua/t/108-timer-safe.t +++ b/debian/modules/nginx-lua/t/108-timer-safe.t @@ -1395,4 +1395,3 @@ registered timer lua ngx.timer expired http lua close fake http connection trace: [m][f][g] - diff --git a/debian/modules/nginx-lua/t/109-timer-hup.t b/debian/modules/nginx-lua/t/109-timer-hup.t index 15aaa0e..0864046 100644 --- a/debian/modules/nginx-lua/t/109-timer-hup.t +++ b/debian/modules/nginx-lua/t/109-timer-hup.t @@ -500,4 +500,3 @@ ok --- grep_error_log_out lua found 8191 pending timers --- timeout: 20 - diff --git a/debian/modules/nginx-lua/t/110-etag.t b/debian/modules/nginx-lua/t/110-etag.t index 351fec4..0a94d3d 100644 --- a/debian/modules/nginx-lua/t/110-etag.t +++ b/debian/modules/nginx-lua/t/110-etag.t @@ -81,4 +81,3 @@ If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT --- no_error_log [error] --- skip_nginx: 3: < 1.3.3 - diff --git a/debian/modules/nginx-lua/t/111-req-header-ua.t b/debian/modules/nginx-lua/t/111-req-header-ua.t index 7c980d0..9e501e3 100644 --- a/debian/modules/nginx-lua/t/111-req-header-ua.t +++ b/debian/modules/nginx-lua/t/111-req-header-ua.t @@ -673,4 +673,3 @@ content: konqueror: 1 User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/112-req-header-conn.t b/debian/modules/nginx-lua/t/112-req-header-conn.t index 51df730..51bc8a4 100644 --- a/debian/modules/nginx-lua/t/112-req-header-conn.t +++ b/debian/modules/nginx-lua/t/112-req-header-conn.t @@ -146,4 +146,3 @@ content: conn type: 0 connection: bad --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/113-req-header-cookie.t b/debian/modules/nginx-lua/t/113-req-header-cookie.t index b26b709..4a93053 100644 --- a/debian/modules/nginx-lua/t/113-req-header-cookie.t +++ b/debian/modules/nginx-lua/t/113-req-header-cookie.t @@ -247,4 +247,3 @@ Cookie: boo=123; foo=bar --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/nginx-lua/t/115-quote-sql-str.t index 0c20dfb..66553b1 100644 --- a/debian/modules/nginx-lua/t/115-quote-sql-str.t +++ b/debian/modules/nginx-lua/t/115-quote-sql-str.t @@ -74,4 +74,3 @@ GET /set 'a\Zb\Z' --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/116-raw-req-socket.t b/debian/modules/nginx-lua/t/116-raw-req-socket.t index 6518f0e..ab06ee4 100644 --- a/debian/modules/nginx-lua/t/116-raw-req-socket.t +++ b/debian/modules/nginx-lua/t/116-raw-req-socket.t @@ -876,4 +876,3 @@ request body: hey, hello world --- no_error_log [error] [alert] - diff --git a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t b/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t index 4e3929b..07abadc 100644 --- a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t +++ b/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t @@ -114,4 +114,3 @@ lua tcp socket write timed out server: failed to send: timeout --- no_error_log [alert] - diff --git a/debian/modules/nginx-lua/t/119-config-prefix.t b/debian/modules/nginx-lua/t/119-config-prefix.t index 4581aa1..3f79320 100644 --- a/debian/modules/nginx-lua/t/119-config-prefix.t +++ b/debian/modules/nginx-lua/t/119-config-prefix.t @@ -30,4 +30,3 @@ GET /lua ^prefix: \/\S+$ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/120-re-find.t b/debian/modules/nginx-lua/t/120-re-find.t index 34c0207..73e6134 100644 --- a/debian/modules/nginx-lua/t/120-re-find.t +++ b/debian/modules/nginx-lua/t/120-re-find.t @@ -612,7 +612,7 @@ matched: 你 === TEST 22: just hit match limit --- http_config - lua_regex_match_limit 5600; + lua_regex_match_limit 5000; --- config location /re { content_by_lua_file html/a.lua; @@ -654,7 +654,7 @@ error: pcre_exec() failed: -8 === TEST 23: just not hit match limit --- http_config - lua_regex_match_limit 5700; + lua_regex_match_limit 5100; --- config location /re { content_by_lua_file html/a.lua; @@ -891,3 +891,29 @@ not matched! --- no_error_log [error] + + +=== TEST 31: match with ctx and a pos (anchored by \G) +--- config + location /re { + content_by_lua ' + local ctx = { pos = 3 } + local from, to, err = ngx.re.find("1234, hello", [[(\G[0-9]+)]], "", ctx) + if from then + ngx.say("from: ", from) + ngx.say("to: ", to) + ngx.say("pos: ", ctx.pos) + else + ngx.say("not matched!") + ngx.say("pos: ", ctx.pos) + end + '; + } +--- request + GET /re +--- response_body +from: 3 +to: 4 +pos: 5 +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/121-version.t b/debian/modules/nginx-lua/t/121-version.t index 2b7a306..9000eb3 100644 --- a/debian/modules/nginx-lua/t/121-version.t +++ b/debian/modules/nginx-lua/t/121-version.t @@ -46,4 +46,3 @@ GET /lua ^version: \d+$ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/122-worker.t b/debian/modules/nginx-lua/t/122-worker.t index fa42b1d..b74c81f 100644 --- a/debian/modules/nginx-lua/t/122-worker.t +++ b/debian/modules/nginx-lua/t/122-worker.t @@ -79,4 +79,3 @@ worker pid: \d+ worker pid is correct\. --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/123-lua-path.t b/debian/modules/nginx-lua/t/123-lua-path.t index da97909..23681a9 100644 --- a/debian/modules/nginx-lua/t/123-lua-path.t +++ b/debian/modules/nginx-lua/t/123-lua-path.t @@ -68,4 +68,3 @@ GET /lua [error] --- error_log eval qr/\[alert\] .*? lua_code_cache is off/ - diff --git a/debian/modules/nginx-lua/t/124-init-worker.t b/debian/modules/nginx-lua/t/124-init-worker.t index d6ea675..22a943e 100644 --- a/debian/modules/nginx-lua/t/124-init-worker.t +++ b/debian/modules/nginx-lua/t/124-init-worker.t @@ -447,7 +447,7 @@ warn(): Thu, 01 Jan 1970 01:34:38 GMT --- timeout: 10 --- http_config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; init_worker_by_lua ' -- global diff --git a/debian/modules/nginx-lua/t/125-configure-args.t b/debian/modules/nginx-lua/t/125-configure-args.t index adec129..4160d4e 100644 --- a/debian/modules/nginx-lua/t/125-configure-args.t +++ b/debian/modules/nginx-lua/t/125-configure-args.t @@ -29,4 +29,3 @@ GET /configure_args ^\s*\-\-[^-]+ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/126-shdict-frag.t b/debian/modules/nginx-lua/t/126-shdict-frag.t index 94422fb..5a2aff8 100644 --- a/debian/modules/nginx-lua/t/126-shdict-frag.t +++ b/debian/modules/nginx-lua/t/126-shdict-frag.t @@ -1264,4 +1264,3 @@ ok --- no_error_log [error] --- timeout: 60 - diff --git a/debian/modules/nginx-lua/t/127-uthread-kill.t b/debian/modules/nginx-lua/t/127-uthread-kill.t index 2ab8abe..cc43c62 100644 --- a/debian/modules/nginx-lua/t/127-uthread-kill.t +++ b/debian/modules/nginx-lua/t/127-uthread-kill.t @@ -190,7 +190,7 @@ resolve name done: -2 === TEST 4: kill pending connect --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /lua { content_by_lua ' local ready = false @@ -505,4 +505,3 @@ thread created: zombie [alert] lua tcp socket abort resolver --- error_log - diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t index d3ef3f5..e8434a3 100644 --- a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t +++ b/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t @@ -315,19 +315,24 @@ failed to send request: closed)$ local data = "" local ntm = 0 - local done = false + local aborted = false for i = 1, 3 do - local res, err, part = sock:receive(1) - if not res then - ngx.say("failed to receive: ", err) - return - else - data = data .. res + if not aborted then + local res, err, part = sock:receive(1) + if not res then + ngx.say("failed to receive: ", err) + aborted = true + else + data = data .. res + end end + ngx.sleep(0.001) end - ngx.say("received: ", data) + if not aborted then + ngx.say("received: ", data) + end '; } @@ -350,6 +355,7 @@ F(ngx_http_lua_socket_tcp_finalize_write_part) { --- tcp_query_len: 11 --- no_error_log [error] +--- wait: 0.05 @@ -623,4 +629,3 @@ close: 1 nil --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/nginx-lua/t/129-ssl-socket.t index 9da9a5c..1c3f7cd 100644 --- a/debian/modules/nginx-lua/t/129-ssl-socket.t +++ b/debian/modules/nginx-lua/t/129-ssl-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 219; +plan tests => repeat_each() * 217; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -26,7 +26,7 @@ sub read_file { $cert; } -our $StartComRootCertificate = read_file("t/cert/startcom.crt"); +our $ComodoRootCertificate = read_file("t/cert/comodo-ca.crt"); our $EquifaxRootCertificate = read_file("t/cert/equifax.crt"); our $TestCertificate = read_file("t/cert/test.crt"); our $TestCertificateKey = read_file("t/cert/test.key"); @@ -125,7 +125,7 @@ SSL reused session === TEST 2: no SNI, no verify --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -135,7 +135,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("g.sregex.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -151,7 +151,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: g.sregex.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -179,21 +179,14 @@ SSL reused session GET /t --- response_body connected: 1 -ssl handshake: userdata -sent http request: 57 bytes. -received: HTTP/1.1 401 Unauthorized -close: 1 nil +failed to do SSL handshake: handshake failed --- log_level: debug --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ---- grep_error_log_out eval -qr/^lua ssl save session: ([0-9A-F]+):2 -lua ssl free session: ([0-9A-F]+):1 -$/ +--- grep_error_log_out --- no_error_log lua ssl server name: SSL reused session -[error] [alert] --- timeout: 5 @@ -202,17 +195,17 @@ SSL reused session === TEST 3: SNI, no verify --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; - content_by_lua ' + content_by_lua_block { local sock = ngx.socket.tcp() sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -220,7 +213,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -228,7 +221,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\r\nHost: openresty.org\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -249,7 +242,7 @@ SSL reused session ngx.say("close: ", ok, " ", err) end -- do collectgarbage() - '; + } } --- request @@ -257,8 +250,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -268,7 +261,7 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -280,7 +273,8 @@ SSL reused session === TEST 4: ssl session reuse --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_protocols TLSv1.2; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -293,7 +287,7 @@ SSL reused session local session for i = 1, 2 do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("agentzh.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -301,7 +295,7 @@ SSL reused session ngx.say("connected: ", ok) - session, err = sock:sslhandshake(session, "iscribblet.org") + session, err = sock:sslhandshake(session, "agentzh.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -309,7 +303,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -340,12 +334,12 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. +sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil connected: 1 ssl handshake: userdata -sent http request: 59 bytes. +sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -371,10 +365,10 @@ lua ssl free session === TEST 5: certificate does not match host name (verify) -The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org". +The certificate of "openresty.org" does not contain the name "blah.openresty.org". --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 5; location /t { @@ -386,7 +380,7 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o sock:settimeout(2000) do - local ok, err = sock:connect("agentzh.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -394,13 +388,171 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "blah.agentzh.org", true) + local session, err = sock:sslhandshake(nil, "blah.openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + collectgarbage() + '; + } + +--- user_files eval +">>> trusted.crt +$::ComodoRootCertificate" + +--- request +GET /t +--- response_body_like chomp +\Aconnected: 1 +failed to do SSL handshake: (?:handshake failed|certificate host mismatch) +failed to send http request: closed +\z + +--- log_level: debug +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log_out +--- error_log +lua ssl server name: "blah.openresty.org" +--- no_error_log +SSL reused session +[alert] +--- timeout: 5 + + + +=== TEST 6: certificate does not match host name (verify, no log socket errors) +The certificate for "openresty.org" does not contain the name "blah.openresty.org". +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_trusted_certificate ../html/trusted.crt; + lua_socket_log_errors off; + lua_ssl_verify_depth 2; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + do + local ok, err = sock:connect("openresty.org", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local session, err = sock:sslhandshake(nil, "blah.openresty.org", true) + if not session then + ngx.say("failed to do SSL handshake: ", err) + else + ngx.say("ssl handshake: ", type(session)) + end + + local req = "GET / HTTP/1.1\\r\\nHost: blah.openresty.org\\r\\nConnection: close\\r\\n\\r\\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + local line, err = sock:receive() + if not line then + ngx.say("failed to receive response status line: ", err) + return + end + + ngx.say("received: ", line) + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + collectgarbage() + '; + } + +--- user_files eval +">>> trusted.crt +$::ComodoRootCertificate" + +--- request +GET /t +--- response_body_like chomp +\Aconnected: 1 +failed to do SSL handshake: (?:handshake failed|certificate host mismatch) +failed to send http request: closed +\z + +--- log_level: debug +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log_out +--- error_log +lua ssl server name: "blah.openresty.org" +--- no_error_log +lua ssl certificate does not match host +SSL reused session +[alert] +--- timeout: 5 + + + +=== TEST 7: certificate does not match host name (no verify) +--- config + server_tokens off; + resolver $TEST_NGINX_RESOLVER ipv6=off; + location /t { + #set $port 5000; + set $port $TEST_NGINX_MEMCACHED_PORT; + + content_by_lua ' + local sock = ngx.socket.tcp() + sock:settimeout(2000) + + do + local ok, err = sock:connect("openresty.org", 443) + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local session, err = sock:sslhandshake(nil, "openresty.org", false) + if not session then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(session)) + local req = "GET / HTTP/1.1\\r\\nHost: agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then @@ -425,170 +577,13 @@ The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.o '; } ---- user_files eval -">>> trusted.crt -$::StartComRootCertificate" - ---- request -GET /t ---- response_body -connected: 1 -failed to do SSL handshake: certificate host mismatch -failed to send http request: closed - ---- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ---- grep_error_log_out ---- error_log -lua ssl server name: "blah.agentzh.org" -lua ssl certificate does not match host "blah.agentzh.org" ---- no_error_log -SSL reused session -[alert] ---- timeout: 5 - - - -=== TEST 6: certificate does not match host name (verify, no log socket errors) -The certificate for "blah.agentzh.org" does not contain the name "blah.agentzh.org". ---- config - server_tokens off; - resolver $TEST_NGINX_RESOLVER; - lua_ssl_trusted_certificate ../html/trusted.crt; - lua_socket_log_errors off; - lua_ssl_verify_depth 2; - location /t { - #set $port 5000; - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua ' - local sock = ngx.socket.tcp() - sock:settimeout(2000) - - do - local ok, err = sock:connect("agentzh.org", 443) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok) - - local session, err = sock:sslhandshake(nil, "blah.agentzh.org", true) - if not session then - ngx.say("failed to do SSL handshake: ", err) - else - ngx.say("ssl handshake: ", type(session)) - end - - local req = "GET / HTTP/1.1\\r\\nHost: blah.agentzh.org\\r\\nConnection: close\\r\\n\\r\\n" - local bytes, err = sock:send(req) - if not bytes then - ngx.say("failed to send http request: ", err) - return - end - - ngx.say("sent http request: ", bytes, " bytes.") - - local line, err = sock:receive() - if not line then - ngx.say("failed to receive response status line: ", err) - return - end - - ngx.say("received: ", line) - - local ok, err = sock:close() - ngx.say("close: ", ok, " ", err) - end -- do - collectgarbage() - '; - } - ---- user_files eval -">>> trusted.crt -$::StartComRootCertificate" - ---- request -GET /t ---- response_body -connected: 1 -failed to do SSL handshake: certificate host mismatch -failed to send http request: closed - ---- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ ---- grep_error_log_out ---- error_log -lua ssl server name: "blah.agentzh.org" ---- no_error_log -lua ssl certificate does not match host -SSL reused session -[alert] ---- timeout: 5 - - - -=== TEST 7: certificate does not match host name (no verify) ---- config - server_tokens off; - resolver $TEST_NGINX_RESOLVER; - location /t { - #set $port 5000; - set $port $TEST_NGINX_MEMCACHED_PORT; - - content_by_lua ' - local sock = ngx.socket.tcp() - sock:settimeout(2000) - - do - local ok, err = sock:connect("agentzh.org", 443) - if not ok then - ngx.say("failed to connect: ", err) - return - end - - ngx.say("connected: ", ok) - - local session, err = sock:sslhandshake(nil, "agentzh.org", false) - if not session then - ngx.say("failed to do SSL handshake: ", err) - return - end - - ngx.say("ssl handshake: ", type(session)) - - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" - local bytes, err = sock:send(req) - if not bytes then - ngx.say("failed to send http request: ", err) - return - end - - ngx.say("sent http request: ", bytes, " bytes.") - - local line, err = sock:receive() - if not line then - ngx.say("failed to receive response status line: ", err) - return - end - - ngx.say("received: ", line) - - local ok, err = sock:close() - ngx.say("close: ", ok, " ", err) - end -- do - collectgarbage() - '; - } - --- request GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 56 bytes. +received: HTTP/1.1 404 Not Found close: 1 nil --- log_level: debug @@ -599,7 +594,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "agentzh.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -608,10 +603,10 @@ SSL reused session -=== TEST 8: iscribblet.org: passing SSL verify +=== TEST 8: openresty.org: passing SSL verify --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -623,7 +618,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -631,7 +626,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -639,7 +634,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -665,15 +660,15 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -684,7 +679,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -696,7 +691,7 @@ SSL reused session === TEST 9: ssl verify depth not enough (with automatic error logging) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 1; location /t { @@ -708,7 +703,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -716,14 +711,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -749,7 +744,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -762,7 +757,7 @@ failed to send http request: closed --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" lua ssl certificate verify error: (20: unable to get local issuer certificate) --- no_error_log SSL reused session @@ -774,7 +769,7 @@ SSL reused session === TEST 10: ssl verify depth not enough (without automatic error logging) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 1; lua_socket_log_errors off; @@ -787,7 +782,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -795,14 +790,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -828,7 +823,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -841,7 +836,7 @@ failed to send http request: closed --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log lua ssl certificate verify error SSL reused session @@ -1010,7 +1005,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -1030,10 +1025,10 @@ SSL reused session -=== TEST 13: iscribblet.org: passing SSL verify with multiple certificates +=== TEST 13: openresty.org: passing SSL verify with multiple certificates --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1045,7 +1040,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1053,7 +1048,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1061,7 +1056,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1088,15 +1083,15 @@ SSL reused session --- user_files eval ">>> trusted.crt $::EquifaxRootCertificate -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1107,7 +1102,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -1119,7 +1114,7 @@ SSL reused session === TEST 14: default cipher --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1129,7 +1124,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1137,7 +1132,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1145,7 +1140,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1174,8 +1169,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1185,8 +1180,8 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" -SSL: TLSv1.2, cipher: "ECDHE-RSA-RC4-SHA SSLv3 +lua ssl server name: "openresty.org" +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 --- no_error_log SSL reused session [error] @@ -1198,8 +1193,8 @@ SSL reused session === TEST 15: explicit cipher configuration --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; - lua_ssl_ciphers RC4-SHA; + resolver $TEST_NGINX_RESOLVER ipv6=off; + lua_ssl_ciphers ECDHE-RSA-AES256-SHA; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1209,7 +1204,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1217,7 +1212,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1225,7 +1220,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1254,8 +1249,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1265,8 +1260,8 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" -SSL: TLSv1.2, cipher: "RC4-SHA SSLv3 +lua ssl server name: "openresty.org" +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-SHA --- no_error_log SSL reused session [error] @@ -1278,7 +1273,7 @@ SSL reused session === TEST 16: explicit ssl protocol configuration --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_protocols TLSv1; location /t { #set $port 5000; @@ -1289,7 +1284,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1297,7 +1292,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1305,7 +1300,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1334,8 +1329,8 @@ GET /t --- response_body connected: 1 ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -1345,8 +1340,8 @@ qr/^lua ssl save session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" -SSL: TLSv1, cipher: "ECDHE-RSA-RC4-SHA SSLv3 +lua ssl server name: "openresty.org" +SSL: TLSv1, cipher: "ECDHE-RSA-AES256-SHA --- no_error_log SSL reused session [error] @@ -1358,7 +1353,7 @@ SSL reused session === TEST 17: unsupported ssl protocol --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_protocols SSLv2; lua_socket_log_errors off; location /t { @@ -1370,7 +1365,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1378,14 +1373,14 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) else ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -1422,7 +1417,7 @@ failed to send http request: closed --- error_log eval [ qr/\[crit\] .*?SSL_do_handshake\(\) failed .*?unsupported protocol/, -'lua ssl server name: "iscribblet.org"', +'lua ssl server name: "openresty.org"', ] --- no_error_log SSL reused session @@ -1432,10 +1427,10 @@ SSL reused session -=== TEST 18: iscribblet.org: passing SSL verify: keepalive (reuse the ssl session) +=== TEST 18: openresty.org: passing SSL verify: keepalive (reuse the ssl session) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1450,7 +1445,7 @@ SSL reused session local session for i = 1, 3 do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1458,7 +1453,7 @@ SSL reused session ngx.say("connected: ", ok) - session, err = sock:sslhandshake(session, "iscribblet.org", true) + session, err = sock:sslhandshake(session, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1477,7 +1472,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -1509,10 +1504,10 @@ SSL reused session -=== TEST 19: iscribblet.org: passing SSL verify: keepalive (no reusing the ssl session) +=== TEST 19: openresty.org: passing SSL verify: keepalive (no reusing the ssl session) --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1526,7 +1521,7 @@ SSL reused session do for i = 1, 3 do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -1534,7 +1529,7 @@ SSL reused session ngx.say("connected: ", ok) - local session, err = sock:sslhandshake(nil, "iscribblet.org", true) + local session, err = sock:sslhandshake(nil, "openresty.org", true) if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -1553,7 +1548,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request GET /t @@ -1592,7 +1587,7 @@ SSL reused session === TEST 20: downstream cosockets do not support ssl handshake --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/trusted.crt; lua_ssl_verify_depth 2; location /t { @@ -1612,7 +1607,7 @@ SSL reused session --- user_files eval ">>> trusted.crt -$::StartComRootCertificate" +$::ComodoRootCertificate" --- request POST /t @@ -1647,7 +1642,7 @@ attempt to call method 'sslhandshake' (a nil value) } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1750,7 +1745,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/test.crt; location /t { @@ -1854,7 +1849,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -1946,7 +1941,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_crl ../html/test.crl; lua_ssl_trusted_certificate ../html/test.crt; lua_socket_log_errors off; @@ -2031,7 +2026,7 @@ SSL reused session === TEST 25: multiple handshake calls --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2042,7 +2037,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -2051,7 +2046,7 @@ SSL reused session ngx.say("connected: ", ok) for i = 1, 2 do - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -2060,7 +2055,7 @@ SSL reused session ngx.say("ssl handshake: ", type(session)) end - local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" + local req = "GET / HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) @@ -2090,8 +2085,8 @@ GET /t connected: 1 ssl handshake: userdata ssl handshake: userdata -sent http request: 59 bytes. -received: HTTP/1.1 200 OK +sent http request: 58 bytes. +received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -2103,7 +2098,7 @@ lua ssl free session: ([0-9A-F]+):2 lua ssl free session: ([0-9A-F]+):1 $/ --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -2115,7 +2110,7 @@ SSL reused session === TEST 26: handshake timed out --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2126,7 +2121,7 @@ SSL reused session sock:settimeout(2000) do - local ok, err = sock:connect("iscribblet.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -2135,7 +2130,7 @@ SSL reused session ngx.say("connected: ", ok) sock:settimeout(1); -- should timeout immediately - local session, err = sock:sslhandshake(nil, "iscribblet.org") + local session, err = sock:sslhandshake(nil, "openresty.org") if not session then ngx.say("failed to do SSL handshake: ", err) return @@ -2157,7 +2152,7 @@ failed to do SSL handshake: timeout --- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ --- grep_error_log_out --- error_log -lua ssl server name: "iscribblet.org" +lua ssl server name: "openresty.org" --- no_error_log SSL reused session [error] @@ -2183,7 +2178,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2254,7 +2249,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2328,7 +2323,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2405,7 +2400,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate ../html/test.crt; location /t { @@ -2510,7 +2505,7 @@ SSL reused session } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; #lua_ssl_trusted_certificate ../html/test.crt; location /t { @@ -2589,7 +2584,7 @@ SSL reused session === TEST 32: handshake, too many arguments --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; location /t { #set $port 5000; set $port $TEST_NGINX_MEMCACHED_PORT; @@ -2598,7 +2593,7 @@ SSL reused session local sock = ngx.socket.tcp() sock:settimeout(2000) - local ok, err = sock:connect("g.sregex.org", 443) + local ok, err = sock:connect("openresty.org", 443) if not ok then ngx.say("failed to connect: ", err) return @@ -2614,7 +2609,7 @@ SSL reused session GET /t --- ignore_response --- error_log eval -qr/\[error\] .* ngx.socket connect: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ +qr/\[error\] .* ngx.socket sslhandshake: expecting 1 ~ 5 arguments \(including the object\), but seen 0/ --- no_error_log [alert] --- timeout: 5 diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/nginx-lua/t/130-internal-api.t index d641ab5..eba0980 100644 --- a/debian/modules/nginx-lua/t/130-internal-api.t +++ b/debian/modules/nginx-lua/t/130-internal-api.t @@ -47,4 +47,3 @@ content req=0x[a-f0-9]{4,} $ --- no_error_log [error] - diff --git a/debian/modules/nginx-lua/t/135-worker-id.t b/debian/modules/nginx-lua/t/135-worker-id.t index 3c1f24d..984f446 100644 --- a/debian/modules/nginx-lua/t/135-worker-id.t +++ b/debian/modules/nginx-lua/t/135-worker-id.t @@ -54,7 +54,7 @@ GET /lua content_by_lua_block { local counters = ngx.shared.counters local ok, c - for i = 1, 45 do + for i = 1, 100 do c = counters:get("c") if c >= 4 then ok = true diff --git a/debian/modules/nginx-lua/t/137-req-misc.t b/debian/modules/nginx-lua/t/137-req-misc.t index 20ada3c..d56f80e 100644 --- a/debian/modules/nginx-lua/t/137-req-misc.t +++ b/debian/modules/nginx-lua/t/137-req-misc.t @@ -59,4 +59,3 @@ not internal GET /test --- response_body internal - diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/nginx-lua/t/138-balancer.t index 8d45c24..ddd0da5 100644 --- a/debian/modules/nginx-lua/t/138-balancer.t +++ b/debian/modules/nginx-lua/t/138-balancer.t @@ -58,8 +58,8 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ } --- request GET /t ---- response_body_like: 500 Internal Server Error ---- error_code: 500 +--- response_body_like: 403 Forbidden +--- error_code: 403 --- error_log [lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream, --- no_error_log eval @@ -431,3 +431,98 @@ qr{\[crit\] .*? connect\(\) to 0\.0\.0\.1:80 failed .*?, upstream: "http://0\.0\ ] --- no_error_log [warn] + + + +=== TEST 15: test if execeed proxy_next_upstream_limit +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; + + proxy_next_upstream_tries 5; + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + local b = require "ngx.balancer" + + if not ngx.ctx.tries then + ngx.ctx.tries = 0 + end + + if ngx.ctx.tries >= 6 then + ngx.log(ngx.ERR, "retry count exceed limit") + ngx.exit(500) + end + + ngx.ctx.tries = ngx.ctx.tries + 1 + print("retry counter: ", ngx.ctx.tries) + + local ok, err = b.set_more_tries(2) + if not ok then + return error("failed to set more tries: ", err) + elseif err then + ngx.log(ngx.WARN, "set more tries: ", err) + end + + assert(b.set_current_peer("127.0.0.1", 81)) + } + } +--- config + location = /t { + proxy_pass http://backend/back; + } + + location = /back { + return 404; + } +--- request + GET /t +--- response_body_like: 502 Bad Gateway +--- error_code: 502 +--- grep_error_log eval: qr/\bretry counter: \w+/ +--- grep_error_log_out +retry counter: 1 +retry counter: 2 +retry counter: 3 +retry counter: 4 +retry counter: 5 + +--- error_log +set more tries: reduced tries due to limit + + + +=== TEST 16: set_more_tries bugfix +--- http_config + lua_package_path "../lua-resty-core/lib/?.lua;;"; + proxy_next_upstream_tries 0; + upstream backend { + server 0.0.0.1; + balancer_by_lua_block { + local balancer = require "ngx.balancer" + local ctx = ngx.ctx + if not ctx.has_run then + ctx.has_run = true + local _, err = balancer.set_more_tries(3) + if err then + ngx.log(ngx.ERR, "failed to set more tries: ", err) + end + end + balancer.set_current_peer("127.0.0.1", 81) + } + } +--- config + location = /t { + proxy_pass http://backend; + } +--- request + GET /t +--- error_code: 502 +--- grep_error_log eval: qr/http next upstream, \d+/ +--- grep_error_log_out +http next upstream, 2 +http next upstream, 2 +http next upstream, 2 +http next upstream, 2 +--- no_error_log +failed to set more tries: reduced tries due to limit +[alert] diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/nginx-lua/t/139-ssl-cert-by.t index b9fd60d..c13044f 100644 --- a/debian/modules/nginx-lua/t/139-ssl-cert-by.t +++ b/debian/modules/nginx-lua/t/139-ssl-cert-by.t @@ -11,7 +11,7 @@ my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0|1\.0\.(?:0|1[^\d]|2[a-d]).*)/) { plan(skip_all => "too old OpenSSL, need 1.0.2e, was $1"); } else { - plan tests => repeat_each() * (blocks() * 6 + 10); + plan tests => repeat_each() * (blocks() * 6 + 6); } $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); @@ -1383,7 +1383,7 @@ uthread: done -=== TEST 17: simple logging - use ssl_certificiate_by_lua* on the http {} level +=== TEST 17: simple logging - use ssl_certificate_by_lua* on the http {} level GitHub openresty/lua-resty-core#42 --- http_config ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } @@ -1574,3 +1574,295 @@ qr/\[error\] .*? send\(\) failed/, --- no_error_log [alert] ssl_certificate_by_lua:1: ssl cert by lua is running! + + + +=== TEST 19: check the count of running timers +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /timers { + default_type 'text/plain'; + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + more_clear_headers Date; + } + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /timers HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +ssl handshake: userdata +sent http request: 59 bytes. +received: HTTP/1.1 200 OK +received: Server: nginx +received: Content-Type: text/plain +received: Content-Length: 2 +received: Connection: close +received: +received: 3 +close: 1 nil + +--- error_log eval +[ +'ssl_certificate_by_lua:1: ssl cert by lua is running!', +'lua ssl server name: "test.com"', +] +--- no_error_log +[error] +[alert] + + + +=== TEST 20: some server {} block missing ssl_certificate_by_lua* handlers (literal server name) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /timers { + default_type 'text/plain'; + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + more_clear_headers Date; + } + } + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test2.com; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /timers HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +qr/\[alert\] .*? no ssl_certificate_by_lua\* defined in server test2\.com\b/, +qr/\[crit\] .*? SSL_do_handshake\(\) failed\b/, +] + + + +=== TEST 21: some server {} block missing ssl_certificate_by_lua* handlers (regex server name) +--- http_config + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name test.com; + + ssl_certificate_by_lua_block { print("ssl cert by lua is running!") } + ssl_certificate ../../cert/test.crt; + ssl_certificate_key ../../cert/test.key; + + server_tokens off; + location /timers { + default_type 'text/plain'; + content_by_lua_block { + ngx.timer.at(0.1, function() ngx.sleep(0.3) end) + ngx.timer.at(0.11, function() ngx.sleep(0.3) end) + ngx.timer.at(0.09, function() ngx.sleep(0.3) end) + ngx.sleep(0.2) + ngx.say(ngx.timer.running_count()) + } + more_clear_headers Date; + } + } + + server { + listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; + server_name ~test2\.com; + } +--- config + server_tokens off; + lua_ssl_trusted_certificate ../../cert/test.crt; + + location /t { + content_by_lua_block { + do + local sock = ngx.socket.tcp() + + sock:settimeout(2000) + + local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") + if not ok then + ngx.say("failed to connect: ", err) + return + end + + ngx.say("connected: ", ok) + + local sess, err = sock:sslhandshake(nil, "test2.com", true) + if not sess then + ngx.say("failed to do SSL handshake: ", err) + return + end + + ngx.say("ssl handshake: ", type(sess)) + + local req = "GET /timers HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" + local bytes, err = sock:send(req) + if not bytes then + ngx.say("failed to send http request: ", err) + return + end + + ngx.say("sent http request: ", bytes, " bytes.") + + while true do + local line, err = sock:receive() + if not line then + -- ngx.say("failed to receive response status line: ", err) + break + end + + ngx.say("received: ", line) + end + + local ok, err = sock:close() + ngx.say("close: ", ok, " ", err) + end -- do + -- collectgarbage() + } + } + +--- request +GET /t +--- response_body +connected: 1 +failed to do SSL handshake: handshake failed + +--- error_log eval +[ +qr/\[alert\] .*? no ssl_certificate_by_lua\* defined in server ~test2\\\.com\b/, +qr/\[crit\] .*? SSL_do_handshake\(\) failed\b/, +] diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/nginx-lua/t/140-ssl-c-api.t index 44ad93d..8734d14 100644 --- a/debian/modules/nginx-lua/t/140-ssl-c-api.t +++ b/debian/modules/nginx-lua/t/140-ssl-c-api.t @@ -561,7 +561,7 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed f:close() local pkey = ffi.C.ngx_http_lua_ffi_parse_pem_priv_key(pkey_data, #pkey_data, errmsg) - if not pkey then + if pkey == nil then ngx.log(ngx.ERR, "failed to parse PEM priv key: ", ffi.string(errmsg[0])) return @@ -626,7 +626,7 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey() failed while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end @@ -711,7 +711,7 @@ lua ssl server name: "test.com" f:close() local pkey = ffi.C.ngx_http_lua_ffi_parse_pem_priv_key(pkey_data, #pkey_data, errmsg) - if not pkey then + if pkey == nil then ngx.log(ngx.ERR, "failed to parse PEM priv key: ", ffi.string(errmsg[0])) return @@ -776,7 +776,7 @@ lua ssl server name: "test.com" while true do local line, err = sock:receive() if not line then - -- ngx.say("failed to recieve response status line: ", err) + -- ngx.say("failed to receive response status line: ", err) break end diff --git a/debian/modules/nginx-lua/t/141-luajit.t b/debian/modules/nginx-lua/t/141-luajit.t index be03fe3..36418d1 100644 --- a/debian/modules/nginx-lua/t/141-luajit.t +++ b/debian/modules/nginx-lua/t/141-luajit.t @@ -1,6 +1,7 @@ # vim:set ft= ts=4 sw=4 et fdm=marker: -use Test::Nginx::Socket::Lua; +use Test::Nginx::Socket::Lua + skip_all => 'no mmap(sbrk(0)) trick since glibc leaks memory in this case'; #worker_connections(1014); #master_on(); diff --git a/debian/modules/nginx-lua/t/142-ssl-session-store.t b/debian/modules/nginx-lua/t/142-ssl-session-store.t index 5c9fad3..73b6e19 100644 --- a/debian/modules/nginx-lua/t/142-ssl-session-store.t +++ b/debian/modules/nginx-lua/t/142-ssl-session-store.t @@ -38,7 +38,7 @@ __DATA__ } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -108,7 +108,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running! } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -183,7 +183,7 @@ API disabled in the context of ssl_session_store_by_lua* } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -275,7 +275,7 @@ my timer run! } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -343,7 +343,7 @@ API disabled in the context of ssl_session_store_by_lua* } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -415,7 +415,7 @@ ngx.exit does not yield and the error code is eaten. } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -488,7 +488,7 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -556,7 +556,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -627,7 +627,7 @@ get_phase: ssl_session_store } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -696,7 +696,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -778,7 +778,7 @@ a.lua:1: ssl store session by lua is running! } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -849,7 +849,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { diff --git a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t b/debian/modules/nginx-lua/t/143-ssl-session-fetch.t index bd800ff..701ead7 100644 --- a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/nginx-lua/t/143-ssl-session-fetch.t @@ -39,7 +39,7 @@ __DATA__ } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -120,7 +120,7 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -204,7 +204,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -305,7 +305,7 @@ qr/my timer run!/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -385,7 +385,7 @@ qr/received memc reply: OK/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -466,7 +466,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -548,7 +548,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -629,7 +629,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -712,7 +712,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; @@ -793,7 +793,7 @@ should never reached here } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -879,7 +879,7 @@ qr/get_phase: ssl_session_fetch/s --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { @@ -1049,7 +1049,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s } --- config server_tokens off; - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { diff --git a/debian/modules/nginx-lua/t/146-malloc-trim.t b/debian/modules/nginx-lua/t/146-malloc-trim.t index 45fb9f2..fc425ce 100644 --- a/debian/modules/nginx-lua/t/146-malloc-trim.t +++ b/debian/modules/nginx-lua/t/146-malloc-trim.t @@ -43,8 +43,9 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -76,13 +77,14 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -114,10 +116,11 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -149,9 +152,10 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +malloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] @@ -330,8 +334,9 @@ ok ok ok --- grep_error_log eval: qr/malloc_trim\(\d+\) returned \d+/ ---- grep_error_log_out -malloc_trim(1) returned 0 +--- grep_error_log_out eval +qr/\Amalloc_trim\(1\) returned [01] +\z/ --- wait: 0.2 --- no_error_log [error] diff --git a/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t b/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t index 52f015a..0689a9b 100644 --- a/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t @@ -315,7 +315,7 @@ lua tcp socket write timed out === TEST 5: connection timeout (tcp) --- config - resolver $TEST_NGINX_RESOLVER; + resolver $TEST_NGINX_RESOLVER ipv6=off; resolver_timeout 3s; location /test { content_by_lua_block { diff --git a/debian/modules/nginx-lua/t/150-fake-delayed-load.t b/debian/modules/nginx-lua/t/150-fake-delayed-load.t new file mode 100644 index 0000000..232bbf3 --- /dev/null +++ b/debian/modules/nginx-lua/t/150-fake-delayed-load.t @@ -0,0 +1,56 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_process_enabled(1); +#log_level('warn'); + +#repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3); + +#no_diff(); +no_long_string(); +#master_on(); +#workers(2); + +run_tests(); + +__DATA__ + +=== TEST 1: lua code cache on +--- http_config + lua_code_cache on; +--- config + location = /cache_on { + content_by_lua_block { + local delayed_load = require("ngx.delayed_load") + ngx.say(type(delayed_load.get_function)) + } + } +--- request +GET /cache_on +--- response_body +function +--- no_error_log +[error] + + + +=== TEST 2: lua code cache off +--- http_config + lua_code_cache off; +--- config + location = /cache_off { + content_by_lua_block { + local delayed_load = require("ngx.delayed_load") + ngx.say(type(delayed_load.get_function)) + } + } +--- request +GET /cache_off +--- response_body +function +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/151-initby-hup.t b/debian/modules/nginx-lua/t/151-initby-hup.t new file mode 100644 index 0000000..f278867 --- /dev/null +++ b/debian/modules/nginx-lua/t/151-initby-hup.t @@ -0,0 +1,168 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +our $SkipReason; + +BEGIN { + if ($ENV{TEST_NGINX_CHECK_LEAK}) { + $SkipReason = "unavailable for the hup tests"; + + } else { + $ENV{TEST_NGINX_USE_HUP} = 1; + undef $ENV{TEST_NGINX_USE_STAP}; + } +} + +use Test::Nginx::Socket::Lua 'no_plan'; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(1); + +#plan tests => repeat_each() * (blocks() * 3 + 3); + +#no_diff(); +#no_long_string(); +no_shuffle(); + +run_tests(); + +__DATA__ + +=== TEST 1: no error in init before HUP +--- http_config + init_by_lua_block { + foo = "hello, FOO" + } +--- config + location /lua { + content_by_lua_block { + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, FOO +--- no_error_log +[error] + + + +=== TEST 2: error in init after HUP (master still alive, worker process still the same as before) +--- http_config + init_by_lua_block { + error("failed to init") + } +--- config + location /lua { + content_by_lua_block { + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, FOO +--- error_log +failed to init +--- reload_fails + + + +=== TEST 3: no error in init again +--- http_config + init_by_lua_block { + foo = "hello, foo" + } +--- config + location /lua { + content_by_lua_block { + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, foo +--- no_error_log +[error] + + + +=== TEST 4: no error in init before HUP, used ngx.shared.DICT +--- http_config + lua_shared_dict dogs 1m; + + init_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", "hello, FOO") + } +--- config + location /lua { + content_by_lua_block { + local dogs = ngx.shared.dogs + local foo = dogs:get("foo") + ngx.say(foo) + } + } +--- request +GET /lua +--- response_body +hello, FOO +--- no_error_log +[error] + + + +=== TEST 5: error in init after HUP, not reloaded but foo have changed. +--- http_config + lua_shared_dict dogs 1m; + + init_by_lua_block { + local dogs = ngx.shared.dogs + dogs:set("foo", "foo have changed") + + error("failed to init") + } +--- config + location /lua { + content_by_lua_block { + ngx.say("HUP reload failed") + } + } +--- request +GET /lua +--- response_body +foo have changed +--- error_log +failed to init +--- reload_fails + + + +=== TEST 6: no error in init again, reload success and foo still have changed. +--- http_config + lua_shared_dict dogs 1m; + + init_by_lua_block { + -- do nothing + } +--- config + location /lua { + content_by_lua_block { + local dogs = ngx.shared.dogs + local foo = dogs:get("foo") + ngx.say(foo) + ngx.say("reload success") + } + } +--- request +GET /lua +--- response_body +foo have changed +reload success +--- no_error_log +[error] diff --git a/debian/modules/nginx-lua/t/152-timer-every.t b/debian/modules/nginx-lua/t/152-timer-every.t new file mode 100644 index 0000000..c8d62e7 --- /dev/null +++ b/debian/modules/nginx-lua/t/152-timer-every.t @@ -0,0 +1,385 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use Test::Nginx::Socket::Lua; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 7 + 2); + +#no_diff(); +no_long_string(); + +our $HtmlDir = html_dir; + +$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; +$ENV{TEST_NGINX_HTML_DIR} = $HtmlDir; + +worker_connections(1024); +run_tests(); + +__DATA__ + +=== TEST 1: simple very +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local function f(premature) + print("elapsed: ", ngx.now() - begin) + print("timer prematurely expired: ", premature) + end + + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + + ngx.say("registered timer") + } + } +--- request +GET /t +--- response_body +registered timer +--- wait: 0.11 +--- no_error_log +[error] +[alert] +[crit] +timer prematurely expired: true +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6])\d*, context: ngx\.timer, client: \d+\.\d+\.\d+\.\d+, server: 0\.0\.0\.0:\d+/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:09|10)\d*, context: ngx\.timer, client: \d+\.\d+\.\d+\.\d+, server: 0\.0\.0\.0:\d+/, +"lua ngx.timer expired", +"http lua close fake http connection", +"timer prematurely expired: false", +] + + + +=== TEST 2: separated global env +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local function f() + foo = 3 + print("foo in timer: ", foo) + end + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.sleep(0.11) + ngx.say("foo = ", foo) + } + } +--- request +GET /t +--- response_body +foo = nil +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 3/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 3: lua variable sharing via upvalue +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local foo = 0 + local function f() + foo = foo + 3 + print("foo in timer: ", foo) + end + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.11) + ngx.say("foo = ", foo) + } + } +--- request +GET /t +--- response_body +registered timer +foo = 6 +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 3/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 6/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 4: create the next timer immediately when timer start running +--- config + location /t { + content_by_lua_block { + local begin = ngx.now() + local foo = 0 + local function f() + foo = foo + 3 + print("foo in timer: ", foo) + + ngx.sleep(0.1) + end + local ok, err = ngx.timer.every(0.05, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + ngx.say("registered timer") + ngx.sleep(0.11) + ngx.say("foo = ", foo) + } + } +--- request +GET /t +--- response_body +registered timer +foo = 6 +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 3/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: foo in timer: 6/, +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 5: callback args +--- config + location /t { + content_by_lua_block { + local n = 0 + + local function f(premature, a, b, c) + n = n + 1 + print("the ", n, " time, args: ", a, ", ", b, ", ", c) + + a, b, c = 0, 0, 0 + end + + local ok, err = ngx.timer.every(0.05, f, 1, 2) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + + ngx.say("registered timer") + ngx.sleep(0.11) + } + } +--- request +GET /t +--- response_body +registered timer +--- wait: 0.12 +--- no_error_log +[error] +[alert] +[crit] +--- error_log eval +[ +"the 1 time, args: 1, 2, nil", +"the 2 time, args: 1, 2, nil", +"lua ngx.timer expired", +"http lua close fake http connection" +] + + + +=== TEST 6: memory leak check +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + -- do nothing + end + + for i = 1, 100 do + local ok, err = ngx.timer.every(0.1, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + + ngx.say("registered timer") + + collectgarbage("collect") + local start = collectgarbage("count") + + ngx.sleep(0.21) + + collectgarbage("collect") + local growth1 = collectgarbage("count") - start + + ngx.sleep(0.51) + + collectgarbage("collect") + local growth2 = collectgarbage("count") - start + + ngx.say("growth1 == growth2: ", growth1 == growth2) + } + } +--- request +GET /t +--- response_body +registered timer +growth1 == growth2: true +--- no_error_log +[error] +[alert] +[crit] +--- timeout: 8 + + + +=== TEST 7: respect lua_max_pending_timers +--- http_config + lua_max_pending_timers 10; +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + -- do nothing + end + + for i = 1, 11 do + local ok, err = ngx.timer.every(0.1, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + + ngx.say("registered 10 timers") + } + } +--- request +GET /t +--- response_body +failed to set timer: too many pending timers +--- no_error_log +[error] +[alert] +[crit] + + + +=== TEST 8: respect lua_max_running_timers +--- http_config + lua_max_pending_timers 100; + lua_max_running_timers 9; +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + ngx.sleep(0.02) + -- do nothing + end + + for i = 1, 10 do + local ok, err = ngx.timer.every(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + end + + ngx.say("registered 10 timers") + + ngx.sleep(0.03) + } + } +--- request +GET /t +--- response_body +registered 10 timers +--- no_error_log +[error] +[crit] +--- error_log +lua_max_running_timers are not enough + + + +=== TEST 9: lua_code_cache off +FIXME: it is know that this test case leaks memory. +so we skip it in the "check leak" testing mode. +--- http_config + lua_code_cache off; +--- config + location /t { + content_by_lua_block { + local function f() + local a = 1 + -- do nothing + end + + local ok, err = ngx.timer.every(0.01, f) + if not ok then + ngx.say("failed to set timer: ", err) + return + end + + collectgarbage("collect") + ngx.say("registered timer") + + ngx.sleep(0.03) + + collectgarbage("collect") + + ngx.sleep(0.03) + + collectgarbage("collect") + ngx.say("ok") + } + } +--- request +GET /t +--- response_body +registered timer +ok +--- no_error_log +[error] +[crit] +--- no_check_leak diff --git a/debian/modules/nginx-lua/t/153-semaphore-hup.t b/debian/modules/nginx-lua/t/153-semaphore-hup.t new file mode 100644 index 0000000..c85a21d --- /dev/null +++ b/debian/modules/nginx-lua/t/153-semaphore-hup.t @@ -0,0 +1,154 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(10140); +#workers(1); +log_level('warn'); +master_process_enabled(1); +repeat_each(1); + +plan tests => repeat_each() * (blocks() * 3); + +no_long_string(); +#no_diff(); + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + $http_config .= <<'_EOC_'; + lua_package_path "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;"; + lua_shared_dict shdict 4m; + + init_by_lua_block { + require "resty.core" + local process = require "ngx.process" + local ok, err = process.enable_privileged_agent() + if not ok then + ngx.log(ngx.ERR, "failed to enable_privileged_agent: ", err) + end + } + + init_worker_by_lua_block { + local function test(pre) + if pre then + return + end + + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + ngx.log(ngx.ERR, "created semaphore object") + + local function sem_wait() + + local ok, err = sem:wait(100) + if not ok then + ngx.log(ngx.ERR, "err: ", err) + else + ngx.log(ngx.ERR, "wait success") + end + end + + while not ngx.worker.exiting() do + local co = ngx.thread.spawn(sem_wait) + ngx.thread.wait(co) + end + end + + local ok, err = ngx.timer.at(0, test) + if not ok then + ngx.log(ngx.ERR, "failed to create semaphore timer err: ", err) + end + + local function reload(pre) + if pre then + return + end + + shdict = ngx.shared.shdict + local success = shdict:add("reloaded", 1) + if not success then + return + end + + ngx.log(ngx.ERR, "try to reload nginx") + + local f, err = io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r") + if not f then + ngx.say("failed to open nginx.pid: ", err) + return + end + + local pid = f:read() + + f:close() + os.execute("kill -HUP " .. pid) + end + + local typ = require "ngx.process".type + if typ() == "privileged agent" then + local ok, err = ngx.timer.at(0.1, reload) + if not ok then + ngx.log(ngx.ERR, "failed to create semaphore timer err: ", err) + end + end + } +_EOC_ + $block->set_value("http_config", $http_config); +}); + +run_tests(); + +__DATA__ + +=== TEST 1: timer + reload +--- config + location /test { + content_by_lua_block { + ngx.sleep(1) + ngx.say("hello") + } + } +--- request +GET /test +--- response_body +hello +--- grep_error_log eval: qr/created semaphore object|try to reload nginx|semaphore gc wait queue is not empty/ +--- grep_error_log_out +created semaphore object +created semaphore object +try to reload nginx +created semaphore object +created semaphore object +--- skip_nginx: 3: < 1.11.2 +--- no_check_leak +--- wait: 0.2 + + + +=== TEST 2: timer + reload (lua code cache off) +--- http_config + lua_code_cache off; +--- config + location /test { + content_by_lua_block { + ngx.sleep(1) + ngx.say("hello") + } + } +--- request +GET /test +--- response_body +hello +--- grep_error_log eval: qr/created semaphore object|try to reload nginx|semaphore gc wait queue is not empty/ +--- grep_error_log_out +created semaphore object +created semaphore object +try to reload nginx +created semaphore object +created semaphore object +--- skip_nginx: 3: < 1.11.2 +--- no_check_leak +--- wait: 0.2 diff --git a/debian/modules/nginx-lua/t/154-semaphore.t b/debian/modules/nginx-lua/t/154-semaphore.t new file mode 100644 index 0000000..3c1f004 --- /dev/null +++ b/debian/modules/nginx-lua/t/154-semaphore.t @@ -0,0 +1,118 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: +use lib 'lib'; +use Test::Nginx::Socket::Lua; + +#worker_connections(10140); +#workers(1); +#log_level('warn'); + +repeat_each(2); + +plan tests => repeat_each() * (blocks() * 3) + blocks(); + +no_long_string(); +#no_diff(); + +add_block_preprocessor(sub { + my $block = shift; + + my $http_config = $block->http_config || ''; + $http_config .= <<'_EOC_'; + lua_package_path "../lua-resty-core/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;"; + + init_by_lua_block { + require "resty.core" + } +_EOC_ + $block->set_value("http_config", $http_config); +}); + +run_tests(); + +__DATA__ + +=== TEST 1: timer + shutdown error log +--- config + location /test { + content_by_lua_block { + local function test(pre) + + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function sem_wait() + + local ok, err = sem:wait(10) + if not ok then + ngx.log(ngx.ERR, "err: ", err) + else + ngx.log(ngx.ERR, "wait success") + end + end + + while not ngx.worker.exiting() do + local co = ngx.thread.spawn(sem_wait) + ngx.thread.wait(co) + end + end + + local ok, err = ngx.timer.at(0, test) + ngx.log(ngx.ERR, "hello, world") + ngx.say("time: ", ok) + } + } +--- request +GET /test +--- response_body +time: 1 +--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/ +--- grep_error_log_out +hello, world +--- shutdown_error_log +--- no_shutdown_error_log +semaphore gc wait queue is not empty + + + +=== TEST 2: timer + shutdown error log (lua code cache off) +--- http_config + lua_code_cache off; +--- config + location /test { + content_by_lua_block { + local function test(pre) + + local semaphore = require "ngx.semaphore" + local sem = semaphore.new() + + local function sem_wait() + + local ok, err = sem:wait(10) + if not ok then + ngx.log(ngx.ERR, "err: ", err) + else + ngx.log(ngx.ERR, "wait success") + end + end + + while not ngx.worker.exiting() do + local co = ngx.thread.spawn(sem_wait) + ngx.thread.wait(co) + end + end + + local ok, err = ngx.timer.at(0, test) + ngx.log(ngx.ERR, "hello, world") + ngx.say("time: ", ok) + } + } +--- request +GET /test +--- response_body +time: 1 +--- grep_error_log eval: qr/hello, world|semaphore gc wait queue is not empty/ +--- grep_error_log_out +hello, world +--- shutdown_error_log +--- no_shutdown_error_log +semaphore gc wait queue is not empty diff --git a/debian/modules/nginx-lua/t/cert/comodo-ca.crt b/debian/modules/nginx-lua/t/cert/comodo-ca.crt new file mode 100644 index 0000000..444461b --- /dev/null +++ b/debian/modules/nginx-lua/t/cert/comodo-ca.crt @@ -0,0 +1,29 @@ +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCBhTELMAkGA1UE +BhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgG +A1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwHhcNMTAwMTE5MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMC +R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UE +ChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR6FSS0gpWsawNJN3Fz0Rn +dJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8Xpz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZ +FGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+ +5eNu/Nio5JIk2kNrYrhV/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pG +x8cgoLEfZd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z+pUX +2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7wqP/0uK3pN/u6uPQL +OvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZahSL0896+1DSJMwBGB7FY79tOi4lu3 +sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVICu9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+C +GCe01a60y1Dma/RMhnEw6abfFobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5 +WdYgGq/yapiqcrxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvlwFTPoCWOAvn9sKIN9SCYPBMt +rFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+ +nq6PK7o9mfjYcwlYRm6mnPTXJ9OV2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSg +tZx8jb8uk2IntznaFxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwW +sRqZCuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiKboHGhfKp +pC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmckejkk9u+UJueBPSZI9FoJA +zMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yLS0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHq +ZJx64SIDqZxubw5lT2yHh17zbqD5daWbQOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk52 +7RH89elWsn2/x20Kk4yl0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7I +LaZRfyHBNVOFBkpdn627G190 +-----END CERTIFICATE----- diff --git a/debian/modules/nginx-lua/t/cert/startcom.crt b/debian/modules/nginx-lua/t/cert/startcom.crt deleted file mode 100644 index a5185ca..0000000 --- a/debian/modules/nginx-lua/t/cert/startcom.crt +++ /dev/null @@ -1,87 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul -F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC -ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w -ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk -aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 -YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg -c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 -aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 -d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG -CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 -dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF -wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS -Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst -0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc -pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl -CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF -P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK -1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm -KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE -JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ -8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm -fyWl8kgAwKQB2j8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW -MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg -Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 -MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi -U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh -cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA -A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk -pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf -OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C -Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT -Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi -HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM -Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w -+2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ -Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 -Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B -26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID -AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE -FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j -ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js -LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM -BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 -Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy -dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh -cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh -YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg -dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp -bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ -YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT -TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ -9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 -jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW -FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz -ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 -ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L -EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu -L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq -yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC -O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V -um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh -NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= ------END CERTIFICATE----- diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config new file mode 100644 index 0000000..a5fa6fb --- /dev/null +++ b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config @@ -0,0 +1,3 @@ +ngx_addon_name="ngx_http_lua_fake_delayed_load_module" +HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_lua_fake_delayed_load_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_lua_fake_delayed_load_module.c" diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c new file mode 100644 index 0000000..2898255 --- /dev/null +++ b/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c @@ -0,0 +1,77 @@ +/* + * This fake_delayed_load delayed load module was used to reproduce + * a bug in ngx_lua's function ngx_http_lua_add_package_preload. + */ + + +#include +#include +#include +#include + + +#include "ngx_http_lua_api.h" + + +static ngx_int_t ngx_http_lua_fake_delayed_load_init(ngx_conf_t *cf); +static int ngx_http_lua_fake_delayed_load_preload(lua_State *L); +static int ngx_http_lua_fake_delayed_load_function(lua_State * L); + + +static ngx_http_module_t ngx_http_lua_fake_delayed_load_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_lua_fake_delayed_load_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 */ +}; + +/* flow identify module struct */ +ngx_module_t ngx_http_lua_fake_delayed_load_module = { + NGX_MODULE_V1, + &ngx_http_lua_fake_delayed_load_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_int_t +ngx_http_lua_fake_delayed_load_init(ngx_conf_t *cf) +{ + ngx_http_lua_add_package_preload(cf, "ngx.delayed_load", + ngx_http_lua_fake_delayed_load_preload); + return NGX_OK; +} + + +static int +ngx_http_lua_fake_delayed_load_preload(lua_State *L) +{ + lua_createtable(L, 0, 1); + + lua_pushcfunction(L, ngx_http_lua_fake_delayed_load_function); + lua_setfield(L, -2, "get_function"); + + return 1; +} + + +static int +ngx_http_lua_fake_delayed_load_function(lua_State * L) +{ + return 0; +} diff --git a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c index 42cde55..650f4f7 100644 --- a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c +++ b/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c @@ -1,5 +1,4 @@ -/* Copyright (C) ZHANG Heng (chiyouhen) - * +/* * This fake module was used to reproduce a bug in ngx_lua's * init_worker_by_lua implementation. */ diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/nginx-lua/util/build.sh index 7887fe9..e45c00a 100755 --- a/debian/modules/nginx-lua/util/build.sh +++ b/debian/modules/nginx-lua/util/build.sh @@ -52,6 +52,7 @@ time ngx-build $force $version \ --add-module=$root/../redis2-nginx-module \ --add-module=$root/t/data/fake-module \ --add-module=$root/t/data/fake-shm-module \ + --add-module=$root/t/data/fake-delayed-load-module \ --with-http_gunzip_module \ --with-http_dav_module \ --with-select_module \ diff --git a/debian/modules/nginx-lua/util/gdbinit b/debian/modules/nginx-lua/util/gdbinit deleted file mode 100644 index 1508c64..0000000 --- a/debian/modules/nginx-lua/util/gdbinit +++ /dev/null @@ -1,415 +0,0 @@ -# This gdb script provides several useful routines for debugging ngx_lua or -# standalone Lua/LuaJIT. -# -# You need gdb >= v7.3 to make this script working correctly. -# -# Installation: place it at $HOME/.gdbinit -# -# -- chaoslawful gmail com - -#### Lua type defines #### - -set $__LUA_TNONE = -1 -set $__LUA_TNIL = 0 -set $__LUA_TBOOLEAN = 1 -set $__LUA_TLIGHTUSERDATA = 2 -set $__LUA_TNUMBER = 3 -set $__LUA_TSTRING = 4 -set $__LUA_TTABLE = 5 -set $__LUA_TFUNCTION = 6 -set $__LUA_TUSERDATA = 7 -set $__LUA_TTHREAD = 8 - -#### Lua constants #### - -set $__LUA_GLOBALSINDEX = -10002 -set $__LUA_ENVIRONINDEX = -10001 -set $__LUA_REGISTRYINDEX = -10000 - -#### Auxiliary methods #### - -define __lua_debug_instance - if !$__lua_debug_instance - set $__lua_debug_instance = (lua_Debug*)malloc(sizeof(lua_Debug)) - end -end - -define __free_lua_debug_instance - if $__lua_debug_instance - set $rc = free($__lua_debug_instance) - set $__lua_debug_instance = 0 - end -end - -set $__BUCKET_SIZE = 16 -define __set_instance - if !$__set_instance - set $__set_instance = (void*(*(*))[2])malloc($__BUCKET_SIZE*sizeof(void*(*)[2])) - set $rc = memset($__set_instance, 0, $__BUCKET_SIZE*sizeof(void*(*)[2])) - end -end - -define __free_set_instance - if $__set_instance - __set_clean - set $rc = free($__set_instance) - set $__set_instance = 0 - end -end - -define __set_add - set $p = (void*)$arg0 - set $__bkt_idx = (int)$p%$__BUCKET_SIZE - - __set_instance - set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] - set $__found = 0 - while $__elem - if (*$__elem)[0] == $p - set $__found = 1 - loop_break - end - set $__elem = (void*(*)[2])(*$__elem)[1] - end - if $__found - set $existed_in_set = 1 - else - set $existed_in_set = 0 - - set $rc = (void*(*)[2])calloc(1, sizeof(void*)*2) - set (*$rc)[0] = $p - set (*$rc)[1] = $__set_instance[$__bkt_idx] - set $__set_instance[$__bkt_idx] = $rc - end -end - -define __set_is_exist - set $p = (void*)$arg0 - set $__bkt_idx = (int)$p%$__BUCKET_SIZE - - __set_instance - set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] - set $__found = 0 - while $__elem - if (*$__elem)[0] == $p - set $__found = 1 - loop_break - end - set $__elem = (void*(*)[2])(*$__elem)[1] - end - if $__found - set $existed_in_set = 1 - else - set $existed_in_set = 0 - end -end - -define __set_clean - __set_instance - - set $__bkt_idx = 0 - while $__bkt_idx < $__BUCKET_SIZE - set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] - while $__elem - set $__next = (void*(*)[2])(*$__elem)[1] - set $rc = free($__elem) - set $__elem = $__next - end - set $__set_instance[$__bkt_idx] = 0 - set $__bkt_idx = $__bkt_idx+1 - end -end - -define hook-quit - __free_lua_debug_instance - __free_set_instance -end - -define hook-detach - __free_lua_debug_instance - __free_set_instance -end - -define hook-disconnect - __free_lua_debug_instance - __free_set_instance -end - -define _lua_pop - set $l = (lua_State*)$arg0 - set $_n = (int)$arg1 - set $_rc = lua_settop($l, -$_n-1) -end - -define _lua_dump_locals - set $l = (lua_State*)$arg0 - set $dbg = (lua_Debug*)$arg1 - set $idx = 1 - - set $rc = lua_getlocal($l, $dbg, $idx) - if $rc - printf "\t----[[ Locals ]]----\n" - while $rc - printf "\t%d:\t'%s' = ", $idx, $rc - __lua_dump_stack $l -1 - printf "\n" - - _lua_pop $l 1 - set $idx = $idx + 1 - set $rc = lua_getlocal($l, $dbg, $idx) - end - else - printf "\tNo locals!\n" - end - printf "\n" -end - -define _lua_dump_upvalues - set $l = (lua_State*)$arg0 - set $dbg = (lua_Debug*)$arg1 - set $idx = 1 - - set $rc = lua_getinfo($l, "f", $dbg) - if $rc - set $rc = lua_getupvalue($l, -1, $idx) - if $rc - printf "\t----[[ Upvalues ]]----\n" - while $rc - printf "\t%d:\t'%s' = ", $idx, $rc - __lua_dump_stack $l -1 - printf "\n" - - _lua_pop $l 1 - set $idx = $idx + 1 - set $rc = lua_getupvalue($l, -1, $idx) - end - else - printf "\tNo upvalues!\n" - end - _lua_pop $l 1 - else - printf "\tFailed to get function closure!\n" - end - printf "\n" -end - -define __lua_dump_stack - __set_clean - __lua_dump_stack_aux $arg0 $arg1 0 -end - -define __lua_dump_stack_aux - set $l = (lua_State*)$arg0 - set $nidx_$arg2 = (int)$arg1 - set $cidx_$arg2 = (int)$arg2+1 - - # relative stack index to absolute index - if $nidx_$arg2 < 0 && $nidx_$arg2 > $__LUA_REGISTRYINDEX - set $nidx_$arg2 = $nidx_$arg2 + (int)lua_gettop($l) + 1 - end - - set $vt_$arg2 = (int)lua_type($l, $nidx_$arg2) - - if $vt_$arg2 == $__LUA_TNONE - echo - end - if $vt_$arg2 == $__LUA_TNIL - echo (nil) - end - if $vt_$arg2 == $__LUA_TBOOLEAN - printf "(bool) %d", lua_toboolean($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TLIGHTUSERDATA - printf "(ludata) %p", lua_touserdata($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TNUMBER - printf "%g", lua_tonumber($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TSTRING - set $tmplen = (size_t*)malloc(sizeof(size_t)) - set $tmp = lua_pushvalue($l, $nidx_$arg2) - set $tmp = lua_tolstring($l, -1, $tmplen) -#printf "(string:%d) ", *$tmplen - eval "output/r *(const char (*)[%d])$tmp", *$tmplen - _lua_pop $l 1 - set $tmp = free($tmplen) - end - if $vt_$arg2 == $__LUA_TTABLE - set $rc = lua_topointer($l, $nidx_$arg2) -#printf "(table) %p { ", $rc - printf "{ " - __set_add $rc - if $existed_in_set - printf "... " - else - set $rc = lua_pushnil($l) - set $rc = lua_next($l, $nidx_$arg2) - while $rc != 0 - printf "[" - __lua_dump_stack_aux $l -2 $cidx_$arg2 - printf "]" - printf " = " - __lua_dump_stack_aux $l -1 $cidx_$arg2 - printf ", " - _lua_pop $l 1 - set $rc = lua_next($l, $nidx_$arg2) - end - end - printf "}" - end - if $vt_$arg2 == $__LUA_TFUNCTION - printf "(func) %p", lua_topointer($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TUSERDATA - printf "(udata) %p", lua_topointer($l, $nidx_$arg2) - end - if $vt_$arg2 == $__LUA_TTHREAD - printf "(thread) %p", lua_topointer($l, $nidx_$arg2) - else - if $vt_$arg2 > $__LUA_TTHREAD || $vt_$arg2 < 0 - echo - end - end -end - -#### Command methods #### - -define lbt - if $argc < 1 - echo Please specify Lua state and/or dump flag!\n - else - set $l = (lua_State*)$arg0 - if $argc > 1 - set $dump_local = ($arg1&1)==1 - set $dump_upvalue = ($arg1&2)==2 - else - set $dump_local = 0 - set $dump_upvalue = 0 - end - - __lua_debug_instance - set $dbg = $__lua_debug_instance - - set $level = 0 - set $rc = lua_getstack($l, $level, $dbg) - while $rc > 0 - set $rc = lua_getinfo($l, "Sln", $dbg) - set $name = $dbg->name - if !$name - set $name = "???" - end - - printf "#%d\t%s\t[%s]\tat %s:%d\n", $level, $name, $dbg->what, $dbg->source, $dbg->currentline - - if $dump_local - _lua_dump_locals $l $dbg - end - if $dump_upvalue - _lua_dump_upvalues $l $dbg - end - - set $level = $level+1 - set $rc = lua_getstack($l, $level, $dbg) - end - end -end - -document lbt -lbt []: Dump the backtrace of the specified Lua state. is a mask value, whose bit 1/2 controls the dump of locals/upvalues at each stack frame correspondingly. So set to 1 dumps only locals; set to 2 dumps only upvalues; and set to 3 dumps both locals and upvalues. -end - -define ll - if $argc != 2 - echo Please specify Lua state and stack frame number (0-based)!\n - else - set $l = (lua_State*)$arg0 - set $level = (int)$arg1 - - __lua_debug_instance - set $dbg = $__lua_debug_instance - - set $rc = lua_getstack($l, $level, $dbg) - if $rc > 0 - _lua_dump_locals $l $dbg - else - echo Failed to get Lua stack frame!\n - end - end -end - -document ll -ll : Dump all local vars in the specified Lua stack frame (0-based). -end - -define lu - if $argc != 2 - echo Please specify Lua state and stack frame number (0-based)!\n - else - set $l = (lua_State*)$arg0 - set $level = (int)$arg1 - - __lua_debug_instance - set $dbg = $__lua_debug_instance - - set $rc = lua_getstack($l, $level, $dbg) - if $rc > 0 - _lua_dump_upvalues $l $dbg - else - echo Failed to get Lua stack frame!\n - end - end -end - -document lu -lu : Dump all upvalues in the specified Lua stack frame (0-based). -end - -define lg - if $argc != 1 - echo Please specify Lua state!\n - else - set $l = (lua_State*)$arg0 - __lua_dump_stack $l $__LUA_GLOBALSINDEX - printf "\n" - end -end - -document lg -lg : Dump all entries in Lua global table. -end - -define lr - if $argc != 1 - echo Please specify Lua state!\n - else - set $l = (lua_State*)$arg0 - __lua_dump_stack $l $__LUA_REGISTRYINDEX - printf "\n" - end -end - -document lr -lr : Dump all entries in Lua registry table. -end - -define ls - if $argc != 1 - echo Please specify Lua state!\n - else - set $l = (lua_State*)$arg0 - set $idx = lua_gettop($l) - while $idx >= 1 - printf "#%d ", $idx - __lua_dump_stack $l $idx - printf "\n" - set $idx = $idx - 1 - end - end -end - -document ls -ls : Dump all entries in call stack. -end - -# vi:ft=gdb ts=4 sw=4 - diff --git a/debian/modules/nginx-lua/util/reindex b/debian/modules/nginx-lua/util/reindex deleted file mode 100755 index bd54c9d..0000000 --- a/debian/modules/nginx-lua/util/reindex +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/perl -#: reindex.pl -#: reindex .t files for Test::Base based test files -#: Copyright (c) 2006 Agent Zhang -#: 2006-04-27 2006-05-09 - -use strict; -use warnings; - -#use File::Copy; -use Getopt::Std; - -my %opts; -getopts('hb:', \%opts); -if ($opts{h} or ! @ARGV) { - die "Usage: reindex [-b 0] t/*.t\n"; -} - -my $init = $opts{b}; -$init = 1 if not defined $init; - -my @files = map glob, @ARGV; -for my $file (@files) { - next if -d $file or $file !~ /\.t_?$/; - reindex($file); -} - -sub reindex { - my $file = $_[0]; - open my $in, $file or - die "Can't open $file for reading: $!"; - my @lines; - my $counter = $init; - my $changed; - while (<$in>) { - s/\r$//; - my $num; - s/ ^ === \s+ TEST \s+ (\d+)/$num=$1; "=== TEST " . $counter++/xie; - next if !defined $num; - if ($num != $counter-1) { - $changed++; - } - } continue { - push @lines, $_; - } - close $in; - my $text = join '', @lines; - $text =~ s/(?x) \n+ === \s+ TEST/\n\n\n\n=== TEST/ixsg; - $text =~ s/__(DATA|END)__\n+=== TEST/__${1}__\n\n=== TEST/; - #$text =~ s/\n+$/\n\n/s; - if (! $changed and $text eq join '', @lines) { - warn "reindex: $file:\tskipped.\n"; - return; - } - #File::Copy::copy( $file, "$file.bak" ); - open my $out, "> $file" or - die "Can't open $file for writing: $!"; - binmode $out; - print $out $text; - close $out; - - warn "reindex: $file:\tdone.\n"; -} - diff --git a/debian/modules/nginx-lua/valgrind.suppress b/debian/modules/nginx-lua/valgrind.suppress index fe161e8..d0bcc56 100644 --- a/debian/modules/nginx-lua/valgrind.suppress +++ b/debian/modules/nginx-lua/valgrind.suppress @@ -149,3 +149,18 @@ fun:main fun:__libc_res_nquerydomain fun:__libc_res_nsearch } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle + fun:main +} +{ + + Memcheck:Cond + obj:* +} From 70cb0befe7496ee84ef10792d03e9f8adc07679b Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 15:16:06 +0300 Subject: [PATCH 021/414] Update OpenSSL 1.1 patch for v0.10.10 --- .../patches/nginx-lua/openssl-1.1.0.patch | 264 +++++------------- 1 file changed, 69 insertions(+), 195 deletions(-) diff --git a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch b/debian/modules/patches/nginx-lua/openssl-1.1.0.patch index a4e42e5..431031b 100644 --- a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch +++ b/debian/modules/patches/nginx-lua/openssl-1.1.0.patch @@ -1,7 +1,7 @@ -From 2f281b9def161d195da4d795fa916b686ac9fd87 Mon Sep 17 00:00:00 2001 +From 525d5a550f5f256af01de1264358086a4cd1ac4a Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:31:32 +0100 -Subject: [PATCH 1/6] bugfix: ssl: don't use SSLv3 in tests +Subject: [PATCH 1/4] bugfix: ssl: don't use SSLv3 in tests. OpenSSL 1.1.0 disables SSLv3 by default. In order to disable SSL session tickets set ssl_session_tickets to off instead. @@ -11,7 +11,7 @@ tickets set ssl_session_tickets to off instead. 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t -index 5c9fad35..b5955199 100644 +index 73b6e197..260fe490 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -32,7 +32,7 @@ __DATA__ @@ -140,7 +140,7 @@ index 5c9fad35..b5955199 100644 server_tokens off; } diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t -index bd800ff8..54f7a4a3 100644 +index 701ead72..3626f0fb 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -33,7 +33,7 @@ __DATA__ @@ -273,25 +273,25 @@ index bd800ff8..54f7a4a3 100644 server_tokens off; } -- -2.11.0 +2.14.1 -From ad8df79bccef37a0bbfd8e40283f3b81cd867760 Mon Sep 17 00:00:00 2001 +From d308b44b3daf7702d9218e2a5620a89a5eca8389 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 12 May 2016 13:12:23 +0100 -Subject: [PATCH 2/6] bugfix: ssl: do not access SSL_SESSION struct directly +Subject: [PATCH 2/4] bugfix: ssl: do not access SSL_SESSION struct directly. In OpenSSL 1.1.0 it was made opaque. --- src/ngx_http_lua_socket_tcp.c | 15 ++--- - t/129-ssl-socket.t | 152 +++++++++++++++++++++--------------------- - 2 files changed, 82 insertions(+), 85 deletions(-) + t/129-ssl-socket.t | 148 +++++++++++++++++++++--------------------- + 2 files changed, 80 insertions(+), 83 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c -index 6db6e2da..18352bfe 100644 +index 382a94de..07164746 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c -@@ -1311,9 +1311,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) +@@ -1316,9 +1316,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) return 2; } @@ -303,7 +303,7 @@ index 6db6e2da..18352bfe 100644 } } -@@ -1577,9 +1576,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, +@@ -1583,9 +1582,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, } else { *ud = ssl_session; @@ -315,7 +315,7 @@ index 6db6e2da..18352bfe 100644 /* set up the __gc metamethod */ lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); -@@ -5356,9 +5354,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) +@@ -5365,9 +5363,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) psession = lua_touserdata(L, 1); if (psession && *psession != NULL) { @@ -328,7 +328,7 @@ index 6db6e2da..18352bfe 100644 ngx_ssl_free_session(*psession); } diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t -index 9da9a5c2..98fb5a2b 100644 +index 1c3f7cd0..0cd1f52f 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -108,10 +108,10 @@ sent http request: 59 bytes. @@ -345,21 +345,16 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- no_error_log lua ssl server name: -@@ -185,10 +185,10 @@ received: HTTP/1.1 401 Unauthorized - close: 1 nil +@@ -182,7 +182,7 @@ connected: 1 + failed to do SSL handshake: handshake failed --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ - --- grep_error_log_out eval --qr/^lua ssl save session: ([0-9A-F]+):2 --lua ssl free session: ([0-9A-F]+):1 -+qr/^lua ssl save session: ([0-9A-F]+) -+lua ssl free session: ([0-9A-F]+) - $/ + --- grep_error_log_out --- no_error_log lua ssl server name: -@@ -262,10 +262,10 @@ received: HTTP/1.1 200 OK +@@ -255,10 +255,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -372,8 +367,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -349,13 +349,13 @@ sent http request: 59 bytes. + lua ssl server name: "openresty.org" +@@ -343,13 +343,13 @@ sent http request: 56 bytes. received: HTTP/1.1 200 OK close: 1 nil @@ -393,25 +388,25 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -437,7 +437,7 @@ failed to do SSL handshake: certificate host mismatch - failed to send http request: closed +@@ -432,7 +432,7 @@ failed to send http request: closed + \z --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "blah.agentzh.org" -@@ -517,7 +517,7 @@ failed to do SSL handshake: certificate host mismatch - failed to send http request: closed + lua ssl server name: "blah.openresty.org" +@@ -512,7 +512,7 @@ failed to send http request: closed + \z --- log_level: debug ---- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+:\d+/ +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "blah.agentzh.org" -@@ -592,10 +592,10 @@ received: HTTP/1.1 200 OK + lua ssl server name: "blah.openresty.org" +@@ -587,10 +587,10 @@ received: HTTP/1.1 404 Not Found close: 1 nil --- log_level: debug @@ -425,7 +420,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -677,10 +677,10 @@ received: HTTP/1.1 200 OK +@@ -672,10 +672,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -439,7 +434,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -759,7 +759,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate +@@ -754,7 +754,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate failed to send http request: closed --- log_level: debug @@ -447,8 +442,8 @@ index 9da9a5c2..98fb5a2b 100644 +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "iscribblet.org" -@@ -838,7 +838,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate + lua ssl server name: "openresty.org" +@@ -833,7 +833,7 @@ failed to do SSL handshake: 20: unable to get local issuer certificate failed to send http request: closed --- log_level: debug @@ -456,8 +451,8 @@ index 9da9a5c2..98fb5a2b 100644 +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "iscribblet.org" -@@ -928,10 +928,10 @@ sent http request: 59 bytes. + lua ssl server name: "openresty.org" +@@ -923,10 +923,10 @@ sent http request: 59 bytes. received: HTTP/1.1 (?:200 OK|302 Found) close: 1 nil \z @@ -471,7 +466,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log lua ssl server name: "www.google.com" -@@ -1018,7 +1018,7 @@ GET /t +@@ -1013,7 +1013,7 @@ GET /t connected: 1 failed to do SSL handshake: 20: unable to get local issuer certificate @@ -480,7 +475,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log lua ssl server name: "www.google.com" -@@ -1100,10 +1100,10 @@ received: HTTP/1.1 200 OK +@@ -1095,10 +1095,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -494,7 +489,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -1179,10 +1179,10 @@ received: HTTP/1.1 200 OK +@@ -1174,10 +1174,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -507,8 +502,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -1259,10 +1259,10 @@ received: HTTP/1.1 200 OK + lua ssl server name: "openresty.org" +@@ -1254,10 +1254,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -521,8 +516,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -1339,10 +1339,10 @@ received: HTTP/1.1 200 OK + lua ssl server name: "openresty.org" +@@ -1334,10 +1334,10 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -535,8 +530,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -1417,7 +1417,7 @@ failed to do SSL handshake: handshake failed + lua ssl server name: "openresty.org" +@@ -1412,7 +1412,7 @@ failed to do SSL handshake: handshake failed failed to send http request: closed --- log_level: debug @@ -545,7 +540,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log eval [ -@@ -1493,10 +1493,10 @@ ssl handshake: userdata +@@ -1488,10 +1488,10 @@ ssl handshake: userdata set keepalive: 1 nil --- log_level: debug @@ -559,7 +554,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -1569,14 +1569,14 @@ ssl handshake: userdata +@@ -1564,14 +1564,14 @@ ssl handshake: userdata set keepalive: 1 nil --- log_level: debug @@ -581,7 +576,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log -@@ -1620,7 +1620,7 @@ hello world +@@ -1615,7 +1615,7 @@ hello world --- response_body_like: 500 Internal Server Error --- error_code: 500 --- log_level: debug @@ -590,7 +585,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log attempt to call method 'sslhandshake' (a nil value) -@@ -1719,10 +1719,10 @@ $::TestCertificateKey +@@ -1714,10 +1714,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -604,7 +599,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- no_error_log lua ssl server name: -@@ -1824,10 +1824,10 @@ $::TestCertificateKey +@@ -1819,10 +1819,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -618,7 +613,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log lua ssl server name: "test.com" -@@ -1917,7 +1917,7 @@ failed to do SSL handshake: handshake failed +@@ -1912,7 +1912,7 @@ failed to do SSL handshake: handshake failed ">>> test.crt $::TestCertificate" @@ -627,7 +622,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log eval qr/SSL_do_handshake\(\) failed .*?unknown protocol/ -@@ -2016,7 +2016,7 @@ $::TestCertificate +@@ -2011,7 +2011,7 @@ $::TestCertificate >>> test.crl $::TestCRL" @@ -636,7 +631,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- error_log lua ssl server name: "test.com" -@@ -2095,12 +2095,12 @@ received: HTTP/1.1 200 OK +@@ -2090,12 +2090,12 @@ received: HTTP/1.1 302 Moved Temporarily close: 1 nil --- log_level: debug @@ -653,8 +648,8 @@ index 9da9a5c2..98fb5a2b 100644 +lua ssl free session: ([0-9A-F]+) $/ --- error_log - lua ssl server name: "iscribblet.org" -@@ -2154,7 +2154,7 @@ connected: 1 + lua ssl server name: "openresty.org" +@@ -2149,7 +2149,7 @@ connected: 1 failed to do SSL handshake: timeout --- log_level: debug @@ -662,8 +657,8 @@ index 9da9a5c2..98fb5a2b 100644 +--- grep_error_log eval: qr/lua ssl (?:set|save|free) session: [0-9A-F]+/ --- grep_error_log_out --- error_log - lua ssl server name: "iscribblet.org" -@@ -2226,7 +2226,7 @@ $::TestCertificateKey + lua ssl server name: "openresty.org" +@@ -2221,7 +2221,7 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -672,7 +667,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- no_error_log lua ssl server name: -@@ -2297,10 +2297,10 @@ $::TestCertificateKey +@@ -2292,10 +2292,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -686,7 +681,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- no_error_log lua ssl server name: -@@ -2377,7 +2377,7 @@ $::TestCertificateKey +@@ -2372,7 +2372,7 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -695,7 +690,7 @@ index 9da9a5c2..98fb5a2b 100644 --- grep_error_log_out --- no_error_log lua ssl server name: -@@ -2479,10 +2479,10 @@ $::TestCertificateKey +@@ -2474,10 +2474,10 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -709,7 +704,7 @@ index 9da9a5c2..98fb5a2b 100644 $/ --- error_log --- no_error_log -@@ -2575,7 +2575,7 @@ $::TestCertificateKey +@@ -2570,7 +2570,7 @@ $::TestCertificateKey >>> test.crt $::TestCertificate" @@ -719,43 +714,14 @@ index 9da9a5c2..98fb5a2b 100644 --- error_log lua ssl certificate verify error: (18: self signed certificate) -- -2.11.0 +2.14.1 -From ee94698edd219607adbd4807f4e5173f6e51ad51 Mon Sep 17 00:00:00 2001 -From: Alessandro Ghedini -Date: Thu, 12 May 2016 13:17:52 +0100 -Subject: [PATCH 3/6] bugfix: ssl: do not set tlsext_status_expected flag - -In OpenSSL 1.1.0 the SSL struct was made opaque, and setting this -flag manually is not required anyway since OpenSSL already does that -automatically when ngx_http_lua_ssl_empty_status_callback() returns -"OK" (which is always), and an OCSP response has been set. ---- - src/ngx_http_lua_ssl_ocsp.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/src/ngx_http_lua_ssl_ocsp.c b/src/ngx_http_lua_ssl_ocsp.c -index 3904aa8e..31b4f243 100644 ---- a/src/ngx_http_lua_ssl_ocsp.c -+++ b/src/ngx_http_lua_ssl_ocsp.c -@@ -490,7 +490,6 @@ ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, - - dd("set ocsp resp: resp_len=%d", (int) resp_len); - (void) SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, resp_len); -- ssl_conn->tlsext_status_expected = 1; - - return NGX_OK; - --- -2.11.0 - - -From 9794d2d1ba577fe4dd8771d69d1ca4a688efe36c Mon Sep 17 00:00:00 2001 +From 473c121668c658140dffdbeb70aa7df1fc48d2a7 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Fri, 10 Jun 2016 13:23:21 +0100 -Subject: [PATCH 4/6] bugfix: ssl: do not access SSL struct directly for - tlsext_status_type +Subject: [PATCH 3/4] bugfix: ssl: do not access SSL struct directly for + tlsext_status_type. In OpenSSL 1.1.0 it was made opaque, and a getter function was added. --- @@ -779,14 +745,14 @@ index 31b4f243..9ec8b509 100644 return NGX_DECLINED; } -- -2.11.0 +2.14.1 -From 4d1f5bdcdade5e3c6ac0c09446ac1dcd8b4006b0 Mon Sep 17 00:00:00 2001 +From 44988918835b8b41e51e75c1618250a560bc11ca Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:19:10 +0100 -Subject: [PATCH 5/6] bugfix: ssl: make SSL session callback build with OpenSSL - 1.1.0 +Subject: [PATCH 4/4] bugfix: ssl: make SSL session callback build with OpenSSL + 1.1.0. --- src/ngx_http_lua_ssl_session_fetchby.c | 9 ++++++--- @@ -795,7 +761,7 @@ Subject: [PATCH 5/6] bugfix: ssl: make SSL session callback build with OpenSSL 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c -index 4c450b56..6212c60d 100644 +index 556b7320..5289cb92 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -171,8 +171,11 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, @@ -839,7 +805,7 @@ index 5a6f96f5..50c6616d 100644 diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c -index b5596bc7..85dbece1 100644 +index bae8273d..dc1fad9b 100644 --- a/src/ngx_http_lua_ssl_session_storeby.c +++ b/src/ngx_http_lua_ssl_session_storeby.c @@ -172,6 +172,8 @@ int @@ -868,97 +834,5 @@ index b5596bc7..85dbece1 100644 dd("setting cctx"); -- -2.11.0 - - -From 97ca52b469fcf4881c06ab26fbc46cbd37d8cf9f Mon Sep 17 00:00:00 2001 -From: Alessandro Ghedini -Date: Mon, 28 Nov 2016 21:01:00 +0000 -Subject: [PATCH 6/6] bugfix: ssl: don't use RC4 in tests - -RC4 ciphers are deprecated and disabled by default in OpenSSL 1.1.0. ---- - t/129-ssl-socket.t | 18 +++++++++--------- - 1 file changed, 9 insertions(+), 9 deletions(-) - -diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t -index 98fb5a2b..1d9c5710 100644 ---- a/t/129-ssl-socket.t -+++ b/t/129-ssl-socket.t -@@ -1129,7 +1129,7 @@ SSL reused session - sock:settimeout(2000) - - do -- local ok, err = sock:connect("iscribblet.org", 443) -+ local ok, err = sock:connect("openresty.org", 443) - if not ok then - ngx.say("failed to connect: ", err) - return -@@ -1137,7 +1137,7 @@ SSL reused session - - ngx.say("connected: ", ok) - -- local session, err = sock:sslhandshake(nil, "iscribblet.org") -+ local session, err = sock:sslhandshake(nil, "openresty.org") - if not session then - ngx.say("failed to do SSL handshake: ", err) - return -@@ -1145,7 +1145,7 @@ SSL reused session - - ngx.say("ssl handshake: ", type(session)) - -- local req = "GET / HTTP/1.1\\r\\nHost: iscribblet.org\\r\\nConnection: close\\r\\n\\r\\n" -+ local req = "GET /en/ HTTP/1.1\\r\\nHost: openresty.org\\r\\nConnection: close\\r\\n\\r\\n" - local bytes, err = sock:send(req) - if not bytes then - ngx.say("failed to send http request: ", err) -@@ -1174,7 +1174,7 @@ GET /t - --- response_body - connected: 1 - ssl handshake: userdata --sent http request: 59 bytes. -+sent http request: 61 bytes. - received: HTTP/1.1 200 OK - close: 1 nil - -@@ -1185,8 +1185,8 @@ qr/^lua ssl save session: ([0-9A-F]+) - lua ssl free session: ([0-9A-F]+) - $/ - --- error_log --lua ssl server name: "iscribblet.org" --SSL: TLSv1.2, cipher: "ECDHE-RSA-RC4-SHA SSLv3 -+lua ssl server name: "openresty.org" -+SSL: TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 - --- no_error_log - SSL reused session - [error] -@@ -1199,7 +1199,7 @@ SSL reused session - --- config - server_tokens off; - resolver $TEST_NGINX_RESOLVER; -- lua_ssl_ciphers RC4-SHA; -+ lua_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256; - location /t { - #set $port 5000; - set $port $TEST_NGINX_MEMCACHED_PORT; -@@ -1266,7 +1266,7 @@ lua ssl free session: ([0-9A-F]+) - $/ - --- error_log - lua ssl server name: "iscribblet.org" --SSL: TLSv1.2, cipher: "RC4-SHA SSLv3 -+SSL: TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 - --- no_error_log - SSL reused session - [error] -@@ -1346,7 +1346,7 @@ lua ssl free session: ([0-9A-F]+) - $/ - --- error_log - lua ssl server name: "iscribblet.org" --SSL: TLSv1, cipher: "ECDHE-RSA-RC4-SHA SSLv3 -+SSL: TLSv1 - --- no_error_log - SSL reused session - [error] --- -2.11.0 +2.14.1 From 7614ff61a9d2985f19dea05d21bfd207bbd7d6e1 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 16:05:03 +0300 Subject: [PATCH 022/414] lua: Drop patch to build against nginx 1.11.11, now included upstream --- debian/modules/README.Modules-versions | 1 - .../nginx-lua/build-nginx-1.1.11.patch | 217 ------------------ debian/modules/patches/nginx-lua/series | 1 - 3 files changed, 219 deletions(-) delete mode 100644 debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions index 6b581cd..ff5f63b 100644 --- a/debian/modules/README.Modules-versions +++ b/debian/modules/README.Modules-versions @@ -25,7 +25,6 @@ README for Modules versions Homepage: https://github.com/openresty/lua-nginx-module Version: v0.10.10 Patch: openssl-1.1.0.patch - Patch: build-nginx-1.11.11.patch Patch: discover-luajit-2.1.patch nginx-upstream-fair diff --git a/debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch b/debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch deleted file mode 100644 index 597cbf8..0000000 --- a/debian/modules/patches/nginx-lua/build-nginx-1.1.11.patch +++ /dev/null @@ -1,217 +0,0 @@ -From 0459a285ca0159d45e73da8bd1164edb5c57cde3 Mon Sep 17 00:00:00 2001 -From: Andrei Belov -Date: Wed, 22 Mar 2017 07:50:57 +0300 -Subject: [PATCH] feature: nginx 1.11.11+ can now build with this module. - -Note: nginx 1.11.11+ are still not an officially supported target yet. -More work needed. - -Closes openresty/lua-nginx-module#1016 - -See also: -http://hg.nginx.org/nginx/rev/e662cbf1b932 ---- - src/ngx_http_lua_common.h | 6 ++++ - src/ngx_http_lua_headers.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++ - src/ngx_http_lua_headers.h | 3 ++ - src/ngx_http_lua_module.c | 13 ++++++++- - 4 files changed, 89 insertions(+), 1 deletion(-) - -diff --git a/src/ngx_http_lua_common.h b/src/ngx_http_lua_common.h -index 079a4dc3..f37d776a 100644 ---- a/src/ngx_http_lua_common.h -+++ b/src/ngx_http_lua_common.h -@@ -199,6 +199,12 @@ struct ngx_http_lua_main_conf_s { - of reqeusts */ - ngx_uint_t malloc_trim_req_count; - -+#if nginx_version >= 1011011 -+ /* the following 2 fields are only used by ngx.req.raw_headers() for now */ -+ ngx_buf_t **busy_buf_ptrs; -+ ngx_int_t busy_buf_ptr_count; -+#endif -+ - unsigned requires_header_filter:1; - unsigned requires_body_filter:1; - unsigned requires_capture_filter:1; -diff --git a/src/ngx_http_lua_headers.c b/src/ngx_http_lua_headers.c -index 23925984..6700ce80 100644 ---- a/src/ngx_http_lua_headers.c -+++ b/src/ngx_http_lua_headers.c -@@ -26,6 +26,9 @@ static int ngx_http_lua_ngx_req_get_headers(lua_State *L); - static int ngx_http_lua_ngx_req_header_clear(lua_State *L); - static int ngx_http_lua_ngx_req_header_set(lua_State *L); - static int ngx_http_lua_ngx_resp_get_headers(lua_State *L); -+#if nginx_version >= 1011011 -+void ngx_http_lua_ngx_raw_header_cleanup(void *data); -+#endif - - - static int -@@ -77,6 +80,11 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - size_t size; - ngx_buf_t *b, *first = NULL; - ngx_int_t i, j; -+#if nginx_version >= 1011011 -+ ngx_buf_t **bb; -+ ngx_chain_t *cl; -+ ngx_http_lua_main_conf_t *lmcf; -+#endif - ngx_connection_t *c; - ngx_http_request_t *r, *mr; - ngx_http_connection_t *hc; -@@ -93,6 +101,10 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - return luaL_error(L, "no request object found"); - } - -+#if nginx_version >= 1011011 -+ lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); -+#endif -+ - ngx_http_lua_check_fake_request(L, r); - - mr = r->main; -@@ -109,8 +121,13 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - dd("hc->nbusy: %d", (int) hc->nbusy); - - if (hc->nbusy) { -+#if nginx_version >= 1011011 -+ dd("hc->busy: %p %p %p %p", hc->busy->buf->start, hc->busy->buf->pos, -+ hc->busy->buf->last, hc->busy->buf->end); -+#else - dd("hc->busy: %p %p %p %p", hc->busy[0]->start, hc->busy[0]->pos, - hc->busy[0]->last, hc->busy[0]->end); -+#endif - } - - dd("request line: %p %p", mr->request_line.data, -@@ -146,9 +163,37 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - dd("size: %d", (int) size); - - if (hc->nbusy) { -+#if nginx_version >= 1011011 -+ if (hc->nbusy > lmcf->busy_buf_ptr_count) { -+ if (lmcf->busy_buf_ptrs) { -+ ngx_free(lmcf->busy_buf_ptrs); -+ } -+ -+ lmcf->busy_buf_ptrs = ngx_alloc(hc->nbusy * sizeof(ngx_buf_t *), -+ r->connection->log); -+ -+ if (lmcf->busy_buf_ptrs == NULL) { -+ return luaL_error(L, "no memory"); -+ } -+ -+ lmcf->busy_buf_ptr_count = hc->nbusy; -+ } -+ -+ bb = lmcf->busy_buf_ptrs; -+ for (cl = hc->busy; cl; cl = cl->next) { -+ *bb++ = cl->buf; -+ } -+#endif - b = NULL; -+ -+#if nginx_version >= 1011011 -+ bb = lmcf->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 - - dd("busy buf: %d: [%.*s]", (int) i, (int) (b->pos - b->start), - b->start); -@@ -223,8 +268,15 @@ ngx_http_lua_ngx_req_raw_header(lua_State *L) - } - - if (hc->nbusy) { -+ -+#if nginx_version >= 1011011 -+ bb = lmcf->busy_buf_ptrs; -+ for (i = hc->nbusy - 1; i >= 0; i--) { -+ b = bb[i]; -+#else - for (i = 0; i < hc->nbusy; i++) { - b = hc->busy[i]; -+#endif - - if (!found) { - if (b != first) { -@@ -1431,4 +1483,20 @@ ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, - #endif /* NGX_LUA_NO_FFI_API */ - - -+#if nginx_version >= 1011011 -+void -+ngx_http_lua_ngx_raw_header_cleanup(void *data) -+{ -+ ngx_http_lua_main_conf_t *lmcf; -+ -+ lmcf = (ngx_http_lua_main_conf_t *) data; -+ -+ if (lmcf->busy_buf_ptrs) { -+ ngx_free(lmcf->busy_buf_ptrs); -+ lmcf->busy_buf_ptrs = NULL; -+ } -+} -+#endif -+ -+ - /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ -diff --git a/src/ngx_http_lua_headers.h b/src/ngx_http_lua_headers.h -index 39f1114c..ee4d21c1 100644 ---- a/src/ngx_http_lua_headers.h -+++ b/src/ngx_http_lua_headers.h -@@ -15,6 +15,9 @@ - void ngx_http_lua_inject_resp_header_api(lua_State *L); - void ngx_http_lua_inject_req_header_api(lua_State *L); - void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L); -+#if nginx_version >= 1011011 -+void ngx_http_lua_ngx_raw_header_cleanup(void *data); -+#endif - - - #endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ -diff --git a/src/ngx_http_lua_module.c b/src/ngx_http_lua_module.c -index 3dc2817b..875f9334 100644 ---- a/src/ngx_http_lua_module.c -+++ b/src/ngx_http_lua_module.c -@@ -28,6 +28,7 @@ - #include "ngx_http_lua_ssl_certby.h" - #include "ngx_http_lua_ssl_session_storeby.h" - #include "ngx_http_lua_ssl_session_fetchby.h" -+#include "ngx_http_lua_headers.h" - - - static void *ngx_http_lua_create_main_conf(ngx_conf_t *cf); -@@ -624,7 +625,7 @@ ngx_http_lua_init(ngx_conf_t *cf) - volatile ngx_cycle_t *saved_cycle; - ngx_http_core_main_conf_t *cmcf; - ngx_http_lua_main_conf_t *lmcf; --#ifndef NGX_LUA_NO_FFI_API -+#if !defined(NGX_LUA_NO_FFI_API) || nginx_version >= 1011011 - ngx_pool_cleanup_t *cln; - #endif - -@@ -716,6 +717,16 @@ ngx_http_lua_init(ngx_conf_t *cf) - cln->handler = ngx_http_lua_sema_mm_cleanup; - #endif - -+#if nginx_version >= 1011011 -+ cln = ngx_pool_cleanup_add(cf->pool, 0); -+ if (cln == NULL) { -+ return NGX_ERROR; -+ } -+ -+ cln->data = lmcf; -+ cln->handler = ngx_http_lua_ngx_raw_header_cleanup; -+#endif -+ - if (lmcf->lua == NULL) { - dd("initializing lua vm"); - --- -2.11.0 - diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/nginx-lua/series index 8edeaf5..7d0f424 100644 --- a/debian/modules/patches/nginx-lua/series +++ b/debian/modules/patches/nginx-lua/series @@ -1,3 +1,2 @@ openssl-1.1.0.patch -build-nginx-1.1.11.patch discover-luajit-2.1.patch From e60711fcc72e83d560fa250fba484f3d541cb5b4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 16:35:53 +0300 Subject: [PATCH 023/414] tests: Fix race between reload and curl's http request Restart nginx to make sure it uses the new configuration. --- debian/tests/ec-x25519 | 2 +- debian/tests/lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/tests/ec-x25519 b/debian/tests/ec-x25519 index a01bc0d..edd4e2f 100644 --- a/debian/tests/ec-x25519 +++ b/debian/tests/ec-x25519 @@ -17,5 +17,5 @@ server { EOF nginx -t -nginx -s reload +invoke-rc.d nginx restart curl --insecure --silent --fail -o /dev/null -w "response_code: %{http_code}\n" https://127.0.0.1/ diff --git a/debian/tests/lua b/debian/tests/lua index 396d8a9..82c1820 100644 --- a/debian/tests/lua +++ b/debian/tests/lua @@ -14,5 +14,5 @@ server { EOF nginx -t -nginx -s reload +invoke-rc.d nginx restart curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ping From 2005e7e35d4c99863c55019cca2a4675f57d8ee0 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 16:53:56 +0300 Subject: [PATCH 024/414] Explicitly disable autoreconf (debhelper 10) Since debhelper 10 systemd & autoreconf are enabled by default, we need systemd and not autoconf so we reverse the logic. While at it, drop not needed autotools dependency. --- debian/control | 3 +-- debian/rules | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index ccb769d..9d46418 100644 --- a/debian/control +++ b/debian/control @@ -5,8 +5,7 @@ Maintainer: Debian Nginx Maintainers , Michael Lustfield , Christos Trochalakis -Build-Depends: autotools-dev, - debhelper (>= 10), +Build-Depends: debhelper (>= 10), po-debconf, dh-systemd (>= 1.5), dpkg-dev (>= 1.15.5), diff --git a/debian/rules b/debian/rules index 3951529..a852d02 100755 --- a/debian/rules +++ b/debian/rules @@ -138,7 +138,7 @@ extras_configure_flags := \ --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module %: - dh $@ --with systemd + dh $@ --without autoreconf override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) From 22aae236484ddf9ace687ee7a846e8420e9927a6 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 17:03:49 +0300 Subject: [PATCH 025/414] Drop Upstart configuration Upstart was removed in Debian stretch --- debian/nginx-common.nginx.upstart | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 debian/nginx-common.nginx.upstart diff --git a/debian/nginx-common.nginx.upstart b/debian/nginx-common.nginx.upstart deleted file mode 100644 index 317bcb0..0000000 --- a/debian/nginx-common.nginx.upstart +++ /dev/null @@ -1,16 +0,0 @@ -description "nginx - small, powerful, scalable web/proxy server" - -start on filesystem and static-network-up -stop on runlevel [016] - -expect fork -respawn - -pre-start script - [ -x /usr/sbin/nginx ] || { stop; exit 0; } - /usr/sbin/nginx -q -t -g 'daemon on; master_process on;' || { stop; exit 0; } -end script - -exec /usr/sbin/nginx -g 'daemon on; master_process on;' - -pre-stop exec /usr/sbin/nginx -s quit From 9ad7cddbce6fae45691b58421e362c579a4e4370 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 28 Aug 2017 17:11:10 +0300 Subject: [PATCH 026/414] Bump Standards to 4.1.0 o Switch all packages to Priority optional, extra is considered deprecated and should be treated as equivalent to optional. nginx-light & extras now inherit optional from the source package. --- debian/control | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 9d46418..e7a598a 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper (>= 10), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.0.0 +Standards-Version: 4.1.0 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git @@ -111,7 +111,6 @@ Description: nginx web/proxy server (standard version) Package: nginx-light Architecture: any -Priority: extra Depends: libnginx-mod-http-echo (= ${binary:Version}), nginx-common (= ${source:Version}), ${misc:Depends}, @@ -139,7 +138,6 @@ Description: nginx web/proxy server (basic version) Package: nginx-extras Architecture: any -Priority: extra Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-cache-purge (= ${binary:Version}), libnginx-mod-http-dav-ext (= ${binary:Version}), From ee4f08f8b48651eb584373af0bb71afd5a4d3c1d Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 29 Aug 2017 10:50:48 +0300 Subject: [PATCH 027/414] Release 1.13.4-1 --- debian/changelog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/debian/changelog b/debian/changelog index 7d350cf..3e671b0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,20 @@ +nginx (1.13.4-1) unstable; urgency=medium + + * New upstream version 1.13.4 + * nginx-lua: + + Add a simple lua autopkgtest + + Discover LuaJIT 2.1 (FTBFS) (Closes: #873319) + + Update to v0.10.10 + + Update OpenSSL 1.1 patch + + Drop patch to build against Nginx 1.11.11, now included upstream + * tests: Fix race between reload and curl's http request + * Explicitly disable autoreconf (debhelper 10) + * Drop Upstart configuration + * Bump Standards to 4.1.0 + + Switch all packages to Priority optional, extra is considered deprecated + + -- Christos Trochalakis Tue, 29 Aug 2017 10:49:03 +0300 + nginx (1.13.3-1) unstable; urgency=high * New upstream version 1.13.3. From 3ebf96c773e9685d526ebe77daaf0baa91e73e04 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 29 Aug 2017 13:04:11 +0300 Subject: [PATCH 028/414] doc: Improve example WordPress configuration Closes: #863343 Thanks: Larry Holish --- debian/help/examples/wordpress | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/debian/help/examples/wordpress b/debian/help/examples/wordpress index 6faf918..2d4c0ab 100644 --- a/debian/help/examples/wordpress +++ b/debian/help/examples/wordpress @@ -34,8 +34,8 @@ server { } # This location block protects against a known attack. It happens if - # the attacker uploads a non-php file and attempts to run it as a - # php file on the server. + # the attacker uploads a non-PHP file and attempts to run it as a + # PHP file on the server. location ~ \..*/.*\.php$ { return 403; } @@ -43,7 +43,7 @@ server { # This is our primary location block. The try_files directive will # attempt to serve the data in the order listed. First try the exact # request (such as an image or text file). If it doesn't exist, see if - # the directory exists. If not, then we move to the last options which + # the directory exists. If not, then we move to the last option which # passes the request to /index.php with the requested query. location / { try_files $uri $uri/ /index.php?q=$uri&$args; @@ -51,7 +51,7 @@ server { # If a PHP file is served, this block will handle the request. This block # works on the assumption you are using php-cgi listening on /tmp/phpcgi.socket. - # Please see the php example (usr/share/doc/nginx/exmaples/php) for more + # Please see the PHP example (/usr/share/doc/nginx-doc/php) for more # information about setting up PHP. # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini location ~ \.php$ { @@ -61,12 +61,11 @@ server { fastcgi_intercept_errors on; fastcgi_pass unix:/tmp/phpcgi.socket; } - - # As mentioned above, Nignx is king of static. If we're serving a static - # file that ends with one of the following extensions, it is best to set - # a very high expires time. This will generate fewer requests for the - # file. These requests will be logged if found, but not if they don't - # exist. + + # If we're serving a static file that ends with one of the following + # extensions, it is best to set a very high expires time. This will + # generate fewer requests for the file. These requests will be logged if + # found, but not if they don't exist. location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; From 3582062c0e7359e6fe9bd08f6b0cea332491554c Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Tue, 5 Sep 2017 10:29:14 +0300 Subject: [PATCH 029/414] Remove upstart configuration file Close: #874319 --- debian/nginx-common.postinst | 4 ++++ debian/nginx-common.postrm | 4 ++++ debian/nginx-common.preinst | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index 2b176f8..f996cec 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -13,6 +13,10 @@ dpkg-maintscript-helper rm_conffile \ dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" +# Handle upstart removal +dpkg-maintscript-helper rm_conffile \ + /etc/init/nginx.conf 1.13.4-2~ -- "$@" + case "$1" in configure) logdir="/var/log/nginx" diff --git a/debian/nginx-common.postrm b/debian/nginx-common.postrm index b0f2e30..9aa06d0 100644 --- a/debian/nginx-common.postrm +++ b/debian/nginx-common.postrm @@ -11,6 +11,10 @@ dpkg-maintscript-helper rm_conffile \ dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" +# Handle upstart removal +dpkg-maintscript-helper rm_conffile \ + /etc/init/nginx.conf 1.13.4-2~ -- "$@" + case "$1" in purge) rm -rf /var/lib/nginx /var/log/nginx /etc/nginx diff --git a/debian/nginx-common.preinst b/debian/nginx-common.preinst index 037c80f..0d2737f 100644 --- a/debian/nginx-common.preinst +++ b/debian/nginx-common.preinst @@ -11,6 +11,10 @@ dpkg-maintscript-helper rm_conffile \ dpkg-maintscript-helper rm_conffile \ /etc/nginx/naxsi-ui.conf 1.6.2-2~ -- "$@" +# Handle upstart removal +dpkg-maintscript-helper rm_conffile \ + /etc/init/nginx.conf 1.13.4-2~ -- "$@" + case "$1" in install) # If we are doing a fresh install, then these files are no longer needed. From 2a7340c231ffc083156ad1af0691c3f25309ecc4 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 6 Sep 2017 10:06:33 +0300 Subject: [PATCH 030/414] New upstream version 1.13.5 --- CHANGES | 15 +++++ CHANGES.ru | 15 +++++ src/core/nginx.h | 4 +- src/core/ngx_conf_file.c | 1 + src/core/ngx_regex.c | 4 +- src/event/ngx_event.h | 4 +- src/event/ngx_event_openssl.c | 56 ++++++++++++++++--- src/event/ngx_event_openssl.h | 2 + src/http/modules/ngx_http_geo_module.c | 3 +- .../modules/ngx_http_range_filter_module.c | 17 +++--- src/http/modules/ngx_http_scgi_module.c | 2 +- .../modules/ngx_http_secure_link_module.c | 3 +- src/http/modules/ngx_http_ssl_module.c | 4 ++ src/http/modules/ngx_http_uwsgi_module.c | 8 +-- src/http/ngx_http_upstream.c | 20 +------ src/os/unix/ngx_files.c | 1 + src/stream/ngx_stream_geo_module.c | 3 +- src/stream/ngx_stream_ssl_module.c | 4 ++ 18 files changed, 119 insertions(+), 47 deletions(-) diff --git a/CHANGES b/CHANGES index cc22571..e46199b 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,19 @@ +Changes with nginx 1.13.5 05 Sep 2017 + + *) Feature: the $ssl_client_escaped_cert variable. + + *) Bugfix: the "ssl_session_ticket_key" directive and the "include" + parameter of the "geo" directive did not work on Windows. + + *) Bugfix: incorrect response length was returned on 32-bit platforms + when requesting more than 4 gigabytes with multiple ranges. + + *) Bugfix: the "expires modified" directive and processing of the + "If-Range" request header line did not use the response last + modification time if proxying without caching was used. + + Changes with nginx 1.13.4 08 Aug 2017 *) Feature: the ngx_http_mirror_module. diff --git a/CHANGES.ru b/CHANGES.ru index f466c4d..73c4164 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,19 @@ +Изменения в nginx 1.13.5 05.09.2017 + + *) Добавление: переменная $ssl_client_escaped_cert. + + *) Исправление: директива ssl_session_ticket_key и параметр include + директивы geo не работали на Windows. + + *) Исправление: на 32-битных платформах при запросе более 4 гигабайт с + помощью нескольких диапазонов возвращалась некорректная длина ответа. + + *) Исправление: директива "expires modified" и обработка строки If-Range + заголовка запроса не учитывали время последнего изменения ответа, + если использовалось проксирование без кэширования. + + Изменения в nginx 1.13.4 08.08.2017 *) Добавление: модуль ngx_http_mirror_module. diff --git a/src/core/nginx.h b/src/core/nginx.h index 3649945..a3c0ef8 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013004 -#define NGINX_VERSION "1.13.4" +#define nginx_version 1013005 +#define NGINX_VERSION "1.13.5" #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 ce8c602..fb28a5a 100644 --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -178,6 +178,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) /* open configuration file */ fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 9939dce..52169f6 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -262,7 +262,7 @@ ngx_pcre_free_studies(void *data) part = &studies->part; elts = part->elts; - for (i = 0 ; /* void */ ; i++) { + for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { @@ -326,7 +326,7 @@ ngx_regex_module_init(ngx_cycle_t *cycle) part = &ngx_pcre_studies->part; elts = part->elts; - for (i = 0 ; /* void */ ; i++) { + for (i = 0; /* void */ ; i++) { if (i >= part->nelts) { if (part->next == NULL) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 053bd16..19fec68 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -152,12 +152,12 @@ struct ngx_event_aio_s { ngx_event_handler_pt handler; ngx_file_t *file; + ngx_fd_t fd; + #if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) ssize_t (*preload_handler)(ngx_buf_t *file); #endif - ngx_fd_t fd; - #if (NGX_HAVE_EVENTFD) int64_t res; #endif diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 07646b6..88a6dbe 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -924,6 +924,7 @@ ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) cln->data = passwords; fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, ngx_open_file_n " \"%s\" failed", file->data); @@ -2905,7 +2906,9 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) file.name = path[i]; file.log = cf->log; - file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0); + 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); @@ -3548,13 +3551,22 @@ ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - const char *servername; + size_t len; + const char *name; + + name = SSL_get_servername(c->ssl->connection, TLSEXT_NAMETYPE_host_name); + + if (name) { + len = ngx_strlen(name); + + s->len = len; + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(s->data, name, len); - servername = SSL_get_servername(c->ssl->connection, - TLSEXT_NAMETYPE_host_name); - if (servername) { - s->data = (u_char *) servername; - s->len = ngx_strlen(servername); return NGX_OK; } @@ -3659,6 +3671,36 @@ ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_escaped_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s) +{ + ngx_str_t cert; + uintptr_t n; + + if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) { + return NGX_ERROR; + } + + if (cert.len == 0) { + s->len = 0; + return NGX_OK; + } + + n = ngx_escape_uri(NULL, cert.data, cert.len, NGX_ESCAPE_URI_COMPONENT); + + s->len = cert.len + n * 2; + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_escape_uri(s->data, cert.data, cert.len, NGX_ESCAPE_URI_COMPONENT); + + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 2a14980..b9a3a96 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -212,6 +212,8 @@ ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_escaped_certificate(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c index 46a8d7c..8262c9d 100644 --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -1400,7 +1400,8 @@ ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, file.name = *name; file.log = cf->log; - file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0); + file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 6256b13..819c5c9 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -463,23 +463,24 @@ static ngx_int_t ngx_http_range_multipart_header(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx) { - size_t len; + off_t len; + size_t size; ngx_uint_t i; ngx_http_range_t *range; ngx_atomic_uint_t boundary; - len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN - + sizeof(CRLF "Content-Type: ") - 1 - + r->headers_out.content_type.len - + sizeof(CRLF "Content-Range: bytes ") - 1; + size = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + + sizeof(CRLF "Content-Type: ") - 1 + + r->headers_out.content_type.len + + sizeof(CRLF "Content-Range: bytes ") - 1; if (r->headers_out.content_type_len == r->headers_out.content_type.len && r->headers_out.charset.len) { - len += sizeof("; charset=") - 1 + r->headers_out.charset.len; + size += sizeof("; charset=") - 1 + r->headers_out.charset.len; } - ctx->boundary_header.data = ngx_pnalloc(r->pool, len); + ctx->boundary_header.data = ngx_pnalloc(r->pool, size); if (ctx->boundary_header.data == NULL) { return NGX_ERROR; } @@ -569,7 +570,7 @@ ngx_http_range_multipart_header(ngx_http_request_t *r, - range[i].content_range.data; len += ctx->boundary_header.len + range[i].content_range.len - + (size_t) (range[i].end - range[i].start); + + (range[i].end - range[i].start); } r->headers_out.content_length_n = len; diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 9204af4..3fb227b 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -819,7 +819,7 @@ ngx_http_scgi_create_request(ngx_http_request_t *r) key = e.pos; #endif code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) & e); + code((ngx_http_script_engine_t *) &e); #if (NGX_DEBUG) val = e.pos; diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c index 907ba6e..536e09a 100644 --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -107,7 +107,7 @@ ngx_http_secure_link_variable(ngx_http_request_t *r, ngx_md5_t md5; ngx_http_secure_link_ctx_t *ctx; ngx_http_secure_link_conf_t *conf; - u_char hash_buf[16], md5_buf[16]; + u_char hash_buf[18], md5_buf[16]; conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module); @@ -154,7 +154,6 @@ ngx_http_secure_link_variable(ngx_http_request_t *r, goto not_found; } - hash.len = 16; hash.data = hash_buf; if (ngx_decode_base64url(&hash, &val) != NGX_OK) { diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 4370275..7d62176 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -299,6 +299,10 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { (uintptr_t) ngx_ssl_get_raw_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_escaped_cert"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_escaped_certificate, + NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_s_dn"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_subject_dn, NGX_HTTP_VAR_CHANGEABLE, 0 }, diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index a2bec4c..124da4d 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -865,7 +865,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) lcode = *(ngx_http_script_len_code_pt *) le.ip; skip_empty = lcode(&le); - for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode (&le)) { + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; } le.ip += sizeof(uintptr_t); @@ -990,7 +990,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; - key_len = (u_char) lcode (&le); + key_len = (u_char) lcode(&le); lcode = *(ngx_http_script_len_code_pt *) le.ip; skip_empty = lcode(&le); @@ -1018,14 +1018,14 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r) *e.pos++ = (u_char) ((key_len >> 8) & 0xff); code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) & e); + code((ngx_http_script_engine_t *) &e); *e.pos++ = (u_char) (val_len & 0xff); *e.pos++ = (u_char) ((val_len >> 8) & 0xff); while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) & e); + code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 6a2b322..73a5882 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -4390,15 +4390,8 @@ ngx_http_upstream_process_last_modified(ngx_http_request_t *r, u = r->upstream; u->headers_in.last_modified = h; - -#if (NGX_HTTP_CACHE) - - if (u->cacheable) { - u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, - h->value.len); - } - -#endif + u->headers_in.last_modified_time = ngx_parse_http_time(h->value.data, + h->value.len); return NGX_OK; } @@ -4940,15 +4933,8 @@ ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h, *ho = *h; r->headers_out.last_modified = ho; - -#if (NGX_HTTP_CACHE) - - if (r->upstream->cacheable) { - r->headers_out.last_modified_time = + r->headers_out.last_modified_time = r->upstream->headers_in.last_modified_time; - } - -#endif return NGX_OK; } diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c index 7fbb7c9..482d327 100644 --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -620,6 +620,7 @@ ngx_create_file_mapping(ngx_file_mapping_t *fm) { 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); diff --git a/src/stream/ngx_stream_geo_module.c b/src/stream/ngx_stream_geo_module.c index 2204546..632fa5a 100644 --- a/src/stream/ngx_stream_geo_module.c +++ b/src/stream/ngx_stream_geo_module.c @@ -1326,7 +1326,8 @@ ngx_stream_geo_include_binary_base(ngx_conf_t *cf, file.name = *name; file.log = cf->log; - file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0); + file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (file.fd == NGX_INVALID_FILE) { err = ngx_errno; if (err != NGX_ENOENT) { diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index 010b98b..1e9973f 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -249,6 +249,10 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { (uintptr_t) ngx_ssl_get_raw_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_escaped_cert"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_escaped_certificate, + NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_s_dn"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_subject_dn, NGX_STREAM_VAR_CHANGEABLE, 0 }, From 1c5a8493cae9ec2fd6f1e258d077bea1a7c01475 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 6 Sep 2017 10:09:50 +0300 Subject: [PATCH 031/414] Adjust rm_conffile to the new version Gbp-Dch: Ignore --- debian/nginx-common.postinst | 2 +- debian/nginx-common.postrm | 2 +- debian/nginx-common.preinst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index f996cec..f83032d 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -15,7 +15,7 @@ dpkg-maintscript-helper rm_conffile \ # Handle upstart removal dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.4-2~ -- "$@" + /etc/init/nginx.conf 1.13.5-1~ -- "$@" case "$1" in configure) diff --git a/debian/nginx-common.postrm b/debian/nginx-common.postrm index 9aa06d0..d6f313a 100644 --- a/debian/nginx-common.postrm +++ b/debian/nginx-common.postrm @@ -13,7 +13,7 @@ dpkg-maintscript-helper rm_conffile \ # Handle upstart removal dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.4-2~ -- "$@" + /etc/init/nginx.conf 1.13.5-1~ -- "$@" case "$1" in purge) diff --git a/debian/nginx-common.preinst b/debian/nginx-common.preinst index 0d2737f..27f21da 100644 --- a/debian/nginx-common.preinst +++ b/debian/nginx-common.preinst @@ -13,7 +13,7 @@ dpkg-maintscript-helper rm_conffile \ # Handle upstart removal dpkg-maintscript-helper rm_conffile \ - /etc/init/nginx.conf 1.13.4-2~ -- "$@" + /etc/init/nginx.conf 1.13.5-1~ -- "$@" case "$1" in install) From cacbf319dba8b15bd02710ad5065516892148a5a Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 6 Sep 2017 10:10:41 +0300 Subject: [PATCH 032/414] Release 1.13.5-1 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3e671b0..396226e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.13.5-1) unstable; urgency=medium + + * New upstream version 1.13.5 + * doc: Improve example WordPress configuration + Thanks to Larry Holish (Closes: #863343) + * Remove upstart conffile (Closes: #874319) + + -- Christos Trochalakis Wed, 06 Sep 2017 10:10:24 +0300 + nginx (1.13.4-1) unstable; urgency=medium * New upstream version 1.13.4 From a5c72db78304846c75c7da22a26e539d4fb07874 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 11 Oct 2017 10:33:46 +0300 Subject: [PATCH 033/414] New upstream version 1.13.6 --- CHANGES | 36 ++++ CHANGES.ru | 36 ++++ conf/mime.types | 166 +++++++++--------- src/core/nginx.h | 4 +- src/core/ngx_connection.c | 4 + src/core/ngx_inet.c | 8 +- src/core/ngx_inet.h | 5 +- src/core/ngx_parse_time.c | 5 +- src/core/ngx_string.c | 16 ++ src/core/ngx_string.h | 2 + src/core/ngx_times.c | 30 +++- src/event/ngx_event_accept.c | 8 + src/http/modules/ngx_http_auth_basic_module.c | 70 ++------ .../modules/ngx_http_upstream_hash_module.c | 24 +-- .../modules/ngx_http_upstream_zone_module.c | 2 +- src/http/ngx_http_upstream.c | 73 ++++++-- src/http/ngx_http_upstream.h | 2 +- src/http/ngx_http_variables.c | 12 ++ src/http/v2/ngx_http_v2.c | 32 ++-- src/http/v2/ngx_http_v2.h | 1 + src/http/v2/ngx_http_v2_filter_module.c | 16 +- src/http/v2/ngx_http_v2_table.c | 6 +- src/os/unix/ngx_user.c | 10 -- src/stream/ngx_stream_proxy_module.c | 14 +- src/stream/ngx_stream_upstream.h | 2 +- src/stream/ngx_stream_upstream_hash_module.c | 24 +-- src/stream/ngx_stream_upstream_zone_module.c | 2 +- src/stream/ngx_stream_variables.c | 14 +- 28 files changed, 408 insertions(+), 216 deletions(-) diff --git a/CHANGES b/CHANGES index e46199b..6a9fdcc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,40 @@ +Changes with nginx 1.13.6 10 Oct 2017 + + *) Bugfix: switching to the next upstream server in the stream module + did not work when using the "ssl_preread" directive. + + *) Bugfix: in the ngx_http_v2_module. + Thanks to Piotr Sikora. + + *) Bugfix: nginx did not support dates after the year 2038 on 32-bit + platforms with 64-bit time_t. + + *) Bugfix: in handling of dates prior to the year 1970 and after the + year 10000. + + *) Bugfix: in the stream module timeouts waiting for UDP datagrams from + upstream servers were not logged or logged at the "info" level + instead of "error". + + *) Bugfix: when using HTTP/2 nginx might return the 400 response without + logging the reason. + + *) Bugfix: in processing of corrupted cache files. + + *) Bugfix: cache control headers were ignored when caching errors + intercepted by error_page. + + *) Bugfix: when using HTTP/2 client request body might be corrupted. + + *) Bugfix: in handling of client addresses when using unix domain + sockets. + + *) Bugfix: nginx hogged CPU when using the "hash ... consistent" + directive in the upstream block if large weights were used and all or + most of the servers were unavailable. + + Changes with nginx 1.13.5 05 Sep 2017 *) Feature: the $ssl_client_escaped_cert variable. diff --git a/CHANGES.ru b/CHANGES.ru index 73c4164..6ea87c9 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,40 @@ +Изменения в nginx 1.13.6 10.10.2017 + + *) Исправление: при использовании директивы ssl_preread в модуле stream + не работало переключение на следующий бэкенд. + + *) Исправление: в модуле ngx_http_v2_module. + Спасибо Piotr Sikora. + + *) Исправление: nginx не поддерживал даты после 2038 года на 32-битных + платформах с 64-битным time_t. + + *) Исправление: в обработке дат до 1970 года и после 10000 года. + + *) Исправление: в модуле stream таймауты ожидания UDP-пакетов от + бэкендов не логгировались или логгировались на уровне info вместо + error. + + *) Исправление: при использовании HTTP/2 nginx мог вернуть ошибку 400, + не указав в логе причину. + + *) Исправление: в обработке повреждённых файлов кэша. + + *) Исправление: при кэшировании ошибок, перехваченных error_page, не + учитывались заголовки управления кэшированием. + + *) Исправление: при использовании HTTP/2 тело запроса могло быть + повреждено. + + *) Исправление: в обработке адресов клиентов при использовании unix + domain сокетов. + + *) Исправление: при использовании директивы "hash ... consistent" в + блоке upstream nginx нагружал процессор, если использовались большие + веса и все или почти все бэкенды были недоступны. + + Изменения в nginx 1.13.5 05.09.2017 *) Добавление: переменная $ssl_client_escaped_cert. diff --git a/conf/mime.types b/conf/mime.types index 89be9a4..8a2348a 100644 --- a/conf/mime.types +++ b/conf/mime.types @@ -1,89 +1,95 @@ 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/png png; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/x-icon ico; - image/x-jng jng; - image/x-ms-bmp bmp; - image/svg+xml svg svgz; - image/webp webp; + 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; - application/font-woff woff; - application/java-archive jar war ear; - application/json json; - application/mac-binhex40 hqx; - application/msword doc; - application/pdf pdf; - application/postscript ps eps ai; - application/rtf rtf; - application/vnd.apple.mpegurl m3u8; - application/vnd.ms-excel xls; - application/vnd.ms-fontobject eot; - application/vnd.ms-powerpoint ppt; - application/vnd.wap.wmlc wmlc; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/x-7z-compressed 7z; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - 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/font-woff woff; + application/java-archive jar war ear; + application/json json; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.apple.mpegurl m3u8; + application/vnd.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/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; - application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; - application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; + 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; } diff --git a/src/core/nginx.h b/src/core/nginx.h index a3c0ef8..5806837 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013005 -#define NGINX_VERSION "1.13.5" +#define nginx_version 1013006 +#define NGINX_VERSION "1.13.6" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 392fc35..9a74758 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -165,6 +165,10 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle) continue; } + if (ls[i].socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + ls[i].socklen = sizeof(ngx_sockaddr_t); + } + switch (ls[i].sockaddr->sa_family) { #if (NGX_HAVE_INET6) diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c index 3bcd3e7..db48b93 100644 --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -182,9 +182,11 @@ ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, ngx_uint_t port) { u_char *p; +#if (NGX_HAVE_INET6 || NGX_HAVE_UNIX_DOMAIN) + size_t n; +#endif struct sockaddr_in *sin; #if (NGX_HAVE_INET6) - size_t n; struct sockaddr_in6 *sin6; #endif #if (NGX_HAVE_UNIX_DOMAIN) @@ -241,7 +243,9 @@ ngx_sock_ntop(struct sockaddr *sa, socklen_t socklen, u_char *text, size_t len, p = ngx_snprintf(text, len, "unix:%Z"); } else { - p = ngx_snprintf(text, len, "unix:%s%Z", saun->sun_path); + n = ngx_strnlen((u_char *) saun->sun_path, + socklen - offsetof(struct sockaddr_un, sun_path)); + p = ngx_snprintf(text, len, "unix:%*s%Z", n, saun->sun_path); } /* we do not include trailing zero in address length */ diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h index 538771e..a3b392e 100644 --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -17,10 +17,11 @@ #define NGX_INET6_ADDRSTRLEN \ (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) #define NGX_UNIX_ADDRSTRLEN \ - (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) + (sizeof("unix:") - 1 + \ + sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) #if (NGX_HAVE_UNIX_DOMAIN) -#define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN) +#define NGX_SOCKADDR_STRLEN NGX_UNIX_ADDRSTRLEN #elif (NGX_HAVE_INET6) #define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1) #else diff --git a/src/core/ngx_parse_time.c b/src/core/ngx_parse_time.c index a5c5034..232ac91 100644 --- a/src/core/ngx_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -44,14 +44,15 @@ ngx_parse_http_time(u_char *value, size_t len) } } - for (p++; p < end; p++) + for (p++; p < end; p++) { if (*p != ' ') { break; } + } if (end - p < 18) { return NGX_ERROR; - } + } if (fmt != isoc) { if (*p < '0' || *p > '9' || *(p + 1) < '0' || *(p + 1) > '9') { diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index de10a06..2ee07bf 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -29,6 +29,22 @@ ngx_strlow(u_char *dst, u_char *src, size_t n) } +size_t +ngx_strnlen(u_char *p, size_t n) +{ + size_t i; + + for (i = 0; i < n; i++) { + + if (p[i] == '\0') { + return i; + } + } + + return n; +} + + u_char * ngx_cpystrn(u_char *dst, u_char *src, size_t n) { diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h index 7363bd2..882ae7c 100644 --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -60,6 +60,8 @@ void ngx_strlow(u_char *dst, u_char *src, size_t n); #define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2) #define ngx_strlen(s) strlen((const char *) s) +size_t ngx_strnlen(u_char *p, size_t n); + #define ngx_strchr(s1, c) strchr((const char *) s1, (int) c) static ngx_inline u_char * diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 843314a..b2edf1a 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -300,27 +300,39 @@ void ngx_gmtime(time_t t, ngx_tm_t *tp) { ngx_int_t yday; - ngx_uint_t n, sec, min, hour, mday, mon, year, wday, days, leap; + ngx_uint_t sec, min, hour, mday, mon, year, wday, days, leap; /* the calculation is valid for positive time_t only */ - n = (ngx_uint_t) t; + if (t < 0) { + t = 0; + } - days = n / 86400; + days = t / 86400; + sec = t % 86400; + + /* + * no more than 4 year digits supported, + * truncate to December 31, 9999, 23:59:59 + */ + + if (days > 2932896) { + days = 2932896; + sec = 86399; + } /* January 1, 1970 was Thursday */ wday = (4 + days) % 7; - n %= 86400; - hour = n / 3600; - n %= 3600; - min = n / 60; - sec = n % 60; + hour = sec / 3600; + sec %= 3600; + min = sec / 60; + sec %= 60; /* * the algorithm based on Gauss' formula, - * see src/http/ngx_http_parse_time.c + * see src/core/ngx_parse_time.c */ /* days since March 1, 1 BC */ diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index 87447d0..7756370 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -164,6 +164,10 @@ ngx_event_accept(ngx_event_t *ev) return; } + if (socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + socklen = sizeof(ngx_sockaddr_t); + } + c->sockaddr = ngx_palloc(c->pool, socklen); if (c->sockaddr == NULL) { ngx_close_accepted_connection(c); @@ -440,6 +444,10 @@ ngx_event_recvmsg(ngx_event_t *ev) c->type = SOCK_DGRAM; c->socklen = msg.msg_namelen; + if (c->socklen > (socklen_t) sizeof(ngx_sockaddr_t)) { + c->socklen = sizeof(ngx_sockaddr_t); + } + #if (NGX_STAT_STUB) (void) ngx_atomic_fetch_add(ngx_stat_active, 1); #endif diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index 4aa684f..2f345b6 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -14,11 +14,6 @@ #define NGX_HTTP_AUTH_BUF_SIZE 2048 -typedef struct { - ngx_str_t passwd; -} ngx_http_auth_basic_ctx_t; - - typedef struct { ngx_http_complex_value_t *realm; ngx_http_complex_value_t user_file; @@ -27,7 +22,7 @@ typedef struct { static ngx_int_t ngx_http_auth_basic_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, - ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm); + ngx_str_t *passwd, ngx_str_t *realm); static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm); static void ngx_http_auth_basic_close(ngx_file_t *file); @@ -103,7 +98,6 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) ngx_str_t pwd, realm, user_file; ngx_uint_t i, level, login, left, passwd; ngx_file_t file; - ngx_http_auth_basic_ctx_t *ctx; ngx_http_auth_basic_loc_conf_t *alcf; u_char buf[NGX_HTTP_AUTH_BUF_SIZE]; enum { @@ -126,13 +120,6 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) return NGX_DECLINED; } - ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module); - - if (ctx) { - return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd, - &realm); - } - rc = ngx_http_auth_basic_user(r); if (rc == NGX_DECLINED) { @@ -237,8 +224,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) pwd.len = i - passwd; pwd.data = &buf[passwd]; - return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, - &realm); + return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm); } break; @@ -276,7 +262,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1); - return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm); + return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm); } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -288,8 +274,8 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) static ngx_int_t -ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, - ngx_http_auth_basic_ctx_t *ctx, ngx_str_t *passwd, ngx_str_t *realm) +ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, ngx_str_t *passwd, + ngx_str_t *realm) { ngx_int_t rc; u_char *encrypted; @@ -301,48 +287,22 @@ ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r, "rc: %i user: \"%V\" salt: \"%s\"", rc, &r->headers_in.user, passwd->data); - if (rc == NGX_OK) { - if (ngx_strcmp(encrypted, passwd->data) == 0) { - return NGX_OK; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "encrypted: \"%s\"", encrypted); - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "user \"%V\": password mismatch", - &r->headers_in.user); - - return ngx_http_auth_basic_set_realm(r, realm); - } - - if (rc == NGX_ERROR) { + if (rc != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - /* rc == NGX_AGAIN */ - - if (ctx == NULL) { - ctx = ngx_palloc(r->pool, sizeof(ngx_http_auth_basic_ctx_t)); - if (ctx == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_auth_basic_module); - - ctx->passwd.len = passwd->len; - passwd->len++; - - ctx->passwd.data = ngx_pstrdup(r->pool, passwd); - if (ctx->passwd.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - + if (ngx_strcmp(encrypted, passwd->data) == 0) { + return NGX_OK; } - /* TODO: add mutex event */ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "encrypted: \"%s\"", encrypted); - return rc; + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "user \"%V\": password mismatch", + &r->headers_in.user); + + return ngx_http_auth_basic_set_realm(r, realm); } diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c index 6c28c64..d67f34d 100644 --- a/src/http/modules/ngx_http_upstream_hash_module.c +++ b/src/http/modules/ngx_http_upstream_hash_module.c @@ -503,6 +503,11 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) ngx_http_upstream_rr_peers_wlock(hp->rrp.peers); + if (hp->tries > 20 || hp->rrp.peers->single) { + ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + pc->cached = 0; pc->connection = NULL; @@ -538,13 +543,6 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } - if (peer->server.len != server->len - || ngx_strncmp(peer->server.data, server->data, server->len) - != 0) - { - continue; - } - if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) @@ -556,6 +554,13 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -577,10 +582,9 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) hp->hash++; hp->tries++; - if (hp->tries >= points->number) { - pc->name = hp->rrp.peers->name; + if (hp->tries > 20) { ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); - return NGX_BUSY; + return hp->get_rr_peer(pc, &hp->rrp); } } diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index d340b48..3229cfe 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -281,7 +281,7 @@ ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers, dst->server.data = NULL; } - dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + dst->sockaddr = ngx_slab_calloc_locked(pool, sizeof(ngx_sockaddr_t)); if (dst->sockaddr == NULL) { goto failed; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 73a5882..2ea521b 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -582,6 +582,9 @@ ngx_http_upstream_init_request(ngx_http_request_t *r) if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { rc = NGX_DECLINED; r->cached = 0; + u->buffer.start = NULL; + u->cache_status = NGX_HTTP_CACHE_MISS; + u->request_sent = 1; } if (ngx_http_upstream_cache_background_update(r, u) != NGX_OK) { @@ -1059,8 +1062,16 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u) return NGX_ERROR; } + if (rc == NGX_AGAIN) { + rc = NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */ + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "cache file \"%s\" contains invalid header", + c->file.name.data); + /* TODO: delete file */ return rc; @@ -2393,9 +2404,20 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) rc = u->reinit_request(r); - if (rc == NGX_OK) { - u->cache_status = NGX_HTTP_CACHE_STALE; - rc = ngx_http_upstream_cache_send(r, u); + if (rc != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, rc); + return NGX_OK; + } + + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); + + if (rc == NGX_DONE) { + return NGX_OK; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_upstream_finalize_request(r, u, rc); @@ -2433,6 +2455,14 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) u->cache_status = NGX_HTTP_CACHE_REVALIDATED; rc = ngx_http_upstream_cache_send(r, u); + if (rc == NGX_DONE) { + return NGX_OK; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (valid == 0) { valid = r->cache->valid_sec; updating = r->cache->updating_sec; @@ -2518,13 +2548,23 @@ ngx_http_upstream_intercept_errors(ngx_http_request_t *r, #if (NGX_HTTP_CACHE) if (r->cache) { - time_t valid; - valid = ngx_http_file_cache_valid(u->conf->cache_valid, status); + if (u->cacheable) { + time_t valid; - if (valid) { - r->cache->valid_sec = ngx_time() + valid; - r->cache->error = status; + valid = r->cache->valid_sec; + + if (valid == 0) { + valid = ngx_http_file_cache_valid(u->conf->cache_valid, + status); + if (valid) { + r->cache->valid_sec = ngx_time() + valid; + } + } + + if (valid) { + r->cache->error = status; + } } ngx_http_file_cache_free(r->cache, u->pipe->temp_file); @@ -4129,9 +4169,20 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, rc = u->reinit_request(r); - if (rc == NGX_OK) { - u->cache_status = NGX_HTTP_CACHE_STALE; - rc = ngx_http_upstream_cache_send(r, u); + if (rc != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, rc); + return; + } + + u->cache_status = NGX_HTTP_CACHE_STALE; + rc = ngx_http_upstream_cache_send(r, u); + + if (rc == NGX_DONE) { + return; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_upstream_finalize_request(r, u, rc); diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index c552ac0..3e714e5 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -98,8 +98,8 @@ typedef struct { ngx_uint_t max_fails; time_t fail_timeout; ngx_msec_t slow_start; + ngx_uint_t down; - unsigned down:1; unsigned backup:1; NGX_COMPAT_BEGIN(6) diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index afeb4ce..ab82177 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -1240,6 +1240,18 @@ ngx_http_variable_binary_remote_addr(ngx_http_request_t *r, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + v->len = r->connection->addr_text.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = r->connection->addr_text.data; + + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) r->connection->sockaddr; diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 7725616..2c62190 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -245,6 +245,8 @@ ngx_http_v2_init(ngx_event_t *rev) h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE; + h2c->table_update = 1; + h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); @@ -746,7 +748,7 @@ ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) type = ngx_http_v2_parse_type(head); ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "process http2 frame type:%ui f:%Xd l:%uz sid:%ui", + "http2 frame type:%ui f:%Xd l:%uz sid:%ui", type, h2c->state.flags, h2c->state.length, h2c->state.sid); if (type >= NGX_HTTP_V2_FRAME_STATES) { @@ -1314,7 +1316,7 @@ ngx_http_v2_state_field_len(ngx_http_v2_connection_t *h2c, u_char *pos, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 hpack %s string length: %i", + "http2 %s string, len:%i", huff ? "encoded" : "raw", len); h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, @@ -1569,7 +1571,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, if (rc == NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 pseudo-header: \":%V: %V\"", + "http2 header: \":%V: %V\"", &header->name, &header->value); return ngx_http_v2_state_header_complete(h2c, pos, end); @@ -1645,7 +1647,7 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 http header: \"%V: %V\"", + "http2 header: \"%V: %V\"", &header->name, &header->value); return ngx_http_v2_state_header_complete(h2c, pos, end); @@ -3335,6 +3337,19 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) || r->schema_start == NULL || r->unparsed_uri.len == 0) { + if (r->method_name.len == 0) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no :method header"); + + } else if (r->schema_start == NULL) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no :schema header"); + + } else { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent no :path header"); + } + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); return NGX_ERROR; } @@ -3360,7 +3375,7 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) ngx_memcpy(p, ending, sizeof(ending)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 http request line: \"%V\"", &r->request_line); + "http2 request line: \"%V\"", &r->request_line); return NGX_OK; } @@ -3574,11 +3589,6 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); } else { - if (stream->preread) { - /* enforce writing preread buffer to file */ - r->request_body_in_file_only = 1; - } - rb->buf = ngx_calloc_buf(r->pool); if (rb->buf != NULL) { @@ -3679,6 +3689,8 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, buf->pos = buf->start = pos; buf->last = buf->end = pos + size; + r->request_body_in_file_only = 1; + } else { if (size > (size_t) (buf->end - buf->last)) { ngx_log_error(NGX_LOG_INFO, fc->log, 0, diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 4804658..42e0eb1 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -144,6 +144,7 @@ struct ngx_http_v2_connection_s { unsigned closed_nodes:8; unsigned settings_ack:1; + unsigned table_update:1; unsigned blocked:1; unsigned goaway:1; }; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 8621e7a..9070785 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -139,6 +139,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) ngx_connection_t *fc; ngx_http_cleanup_t *cln; ngx_http_v2_out_frame_t *frame; + ngx_http_v2_connection_t *h2c; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; u_char addr[NGX_SOCKADDR_STRLEN]; @@ -235,7 +236,11 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } } - len = status ? 1 : 1 + ngx_http_v2_literal_size("418"); + h2c = r->stream->connection; + + len = h2c->table_update ? 1 : 0; + + len += status ? 1 : 1 + ngx_http_v2_literal_size("418"); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -423,6 +428,13 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) 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_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 output header: \":status: %03ui\"", r->headers_out.status); @@ -1257,7 +1269,7 @@ ngx_http_v2_flow_control(ngx_http_v2_connection_t *h2c, ngx_http_v2_stream_t *stream) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2:%ui available windows: conn:%uz stream:%z", + "http2:%ui windows: conn:%uz stream:%z", stream->node->id, h2c->send_window, stream->send_window); if (stream->send_window <= 0) { diff --git a/src/http/v2/ngx_http_v2_table.c b/src/http/v2/ngx_http_v2_table.c index a73748a..62025c4 100644 --- a/src/http/v2/ngx_http_v2_table.c +++ b/src/http/v2/ngx_http_v2_table.c @@ -102,7 +102,7 @@ ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c, ngx_uint_t index, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, "http2 get indexed %s: %ui", - name_only ? "header" : "header name", index); + name_only ? "name" : "header", index); index--; @@ -180,7 +180,7 @@ ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, ngx_http_v2_header_t *entry, **entries; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 add header to hpack table: \"%V: %V\"", + "http2 table add: \"%V: %V\"", &header->name, &header->value); if (h2c->hpack.entries == NULL) { @@ -293,7 +293,7 @@ ngx_http_v2_table_account(ngx_http_v2_connection_t *h2c, size_t size) size += 32; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 hpack table account: %uz free:%uz", + "http2 table account: %uz free:%uz", size, h2c->hpack.free); if (size <= h2c->hpack.free) { diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c index 27c76ef..7ebe2b5 100644 --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -9,16 +9,6 @@ #include -/* - * Solaris has thread-safe crypt() - * Linux has crypt_r(); "struct crypt_data" is more than 128K - * FreeBSD needs the mutex to protect crypt() - * - * TODO: - * ngx_crypt_init() to init mutex - */ - - #if (NGX_CRYPT) #if (NGX_HAVE_GNU_CRYPT_R) diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 0afde1c..9d4b075 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1331,13 +1331,17 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) return; } + ngx_connection_error(pc, NGX_ETIMEDOUT, "upstream timed out"); + if (u->received == 0) { ngx_stream_proxy_next_upstream(s); return; } + + } else { + ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); } - ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out"); ngx_stream_proxy_finalize(s, NGX_STREAM_OK); return; } @@ -1665,13 +1669,17 @@ ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) u = s->upstream; pc = u->peer.connection; - if (u->upstream_out || u->upstream_busy || (pc && pc->buffered)) { + if (pc && pc->buffered) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "pending buffers on next upstream"); + "buffered data on next upstream"); ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; } + if (s->connection->type == SOCK_DGRAM) { + u->upstream_out = NULL; + } + if (u->peer.sockaddr) { u->peer.free(&u->peer, u->peer.data, NGX_PEER_FAILED); u->peer.sockaddr = NULL; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 90076e0..73947f4 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -58,8 +58,8 @@ typedef struct { ngx_uint_t max_fails; time_t fail_timeout; ngx_msec_t slow_start; + ngx_uint_t down; - unsigned down:1; unsigned backup:1; NGX_COMPAT_BEGIN(4) diff --git a/src/stream/ngx_stream_upstream_hash_module.c b/src/stream/ngx_stream_upstream_hash_module.c index cb44fcd..79ad742 100644 --- a/src/stream/ngx_stream_upstream_hash_module.c +++ b/src/stream/ngx_stream_upstream_hash_module.c @@ -505,6 +505,11 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) ngx_stream_upstream_rr_peers_wlock(hp->rrp.peers); + if (hp->tries > 20 || hp->rrp.peers->single) { + ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); + return hp->get_rr_peer(pc, &hp->rrp); + } + pc->connection = NULL; now = ngx_time(); @@ -539,13 +544,6 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } - if (peer->server.len != server->len - || ngx_strncmp(peer->server.data, server->data, server->len) - != 0) - { - continue; - } - if (peer->max_fails && peer->fails >= peer->max_fails && now - peer->checked <= peer->fail_timeout) @@ -557,6 +555,13 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) continue; } + if (peer->server.len != server->len + || ngx_strncmp(peer->server.data, server->data, server->len) + != 0) + { + continue; + } + peer->current_weight += peer->effective_weight; total += peer->effective_weight; @@ -578,10 +583,9 @@ ngx_stream_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data) hp->hash++; hp->tries++; - if (hp->tries >= points->number) { - pc->name = hp->rrp.peers->name; + if (hp->tries > 20) { ngx_stream_upstream_rr_peers_unlock(hp->rrp.peers); - return NGX_BUSY; + return hp->get_rr_peer(pc, &hp->rrp); } } diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 4f72188..80d42fa 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -278,7 +278,7 @@ ngx_stream_upstream_zone_copy_peer(ngx_stream_upstream_rr_peers_t *peers, dst->server.data = NULL; } - dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + dst->sockaddr = ngx_slab_calloc_locked(pool, sizeof(ngx_sockaddr_t)); if (dst->sockaddr == NULL) { goto failed; } diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 45d6e60..95ae12b 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -460,7 +460,7 @@ ngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name, static ngx_int_t ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) - { +{ struct sockaddr_in *sin; #if (NGX_HAVE_INET6) struct sockaddr_in6 *sin6; @@ -481,6 +481,18 @@ ngx_stream_variable_binary_remote_addr(ngx_stream_session_t *s, break; #endif +#if (NGX_HAVE_UNIX_DOMAIN) + case AF_UNIX: + + v->len = s->connection->addr_text.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = s->connection->addr_text.data; + + break; +#endif + default: /* AF_INET */ sin = (struct sockaddr_in *) s->connection->sockaddr; From 515a80bc0a2ead9c5b7b8c5db9172869c0a0eab9 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 11 Sep 2017 17:55:23 +0300 Subject: [PATCH 034/414] mod: Normalize module locations Use the package name to infer module location. This will make it easier to script our maintaining tasks. --- debian/copyright | 28 +++++++-------- .../ChangeLog | 0 .../{nginx-auth-pam => http-auth-pam}/LICENSE | 0 .../README.md | 0 .../{nginx-auth-pam => http-auth-pam}/VERSION | 0 .../{nginx-auth-pam => http-auth-pam}/config | 0 .../ngx_http_auth_pam_module.c | 0 .../CHANGES | 0 .../LICENSE | 0 .../README.md | 0 .../TODO.md | 0 .../config | 0 .../ngx_cache_purge_module.c | 0 .../t/proxy1.t | 0 .../t/proxy1_vars.t | 0 .../t/proxy2.t | 0 .../t/proxy2_vars.t | 0 .../README | 0 .../config | 0 .../ngx_http_dav_ext_module.c | 0 .../modules/{nginx-echo => http-echo}/LICENSE | 0 .../{nginx-echo => http-echo}/README.markdown | 0 .../modules/{nginx-echo => http-echo}/config | 0 .../{nginx-echo => http-echo}/src/ddebug.h | 0 .../src/ngx_http_echo_echo.c | 0 .../src/ngx_http_echo_echo.h | 0 .../src/ngx_http_echo_filter.c | 0 .../src/ngx_http_echo_filter.h | 0 .../src/ngx_http_echo_foreach.c | 0 .../src/ngx_http_echo_foreach.h | 0 .../src/ngx_http_echo_handler.c | 0 .../src/ngx_http_echo_handler.h | 0 .../src/ngx_http_echo_location.c | 0 .../src/ngx_http_echo_location.h | 0 .../src/ngx_http_echo_module.c | 0 .../src/ngx_http_echo_module.h | 0 .../src/ngx_http_echo_request_info.c | 0 .../src/ngx_http_echo_request_info.h | 0 .../src/ngx_http_echo_sleep.c | 0 .../src/ngx_http_echo_sleep.h | 0 .../src/ngx_http_echo_subrequest.c | 0 .../src/ngx_http_echo_subrequest.h | 0 .../src/ngx_http_echo_timer.c | 0 .../src/ngx_http_echo_timer.h | 0 .../src/ngx_http_echo_util.c | 0 .../src/ngx_http_echo_util.h | 0 .../src/ngx_http_echo_var.c | 0 .../src/ngx_http_echo_var.h | 0 .../t/abort-parent.t | 0 .../t/blocking-sleep.t | 0 .../t/echo-after-body.t | 0 .../t/echo-before-body.t | 0 .../t/echo-duplicate.t | 0 .../{nginx-echo => http-echo}/t/echo-timer.t | 0 .../{nginx-echo => http-echo}/t/echo.t | 0 .../{nginx-echo => http-echo}/t/exec.t | 0 .../{nginx-echo => http-echo}/t/filter-used.t | 0 .../t/foreach-split.t | 0 .../{nginx-echo => http-echo}/t/gzip.t | 0 .../modules/{nginx-echo => http-echo}/t/if.t | 0 .../{nginx-echo => http-echo}/t/incr.t | 0 .../t/location-async.t | 0 .../{nginx-echo => http-echo}/t/location.t | 0 .../{nginx-echo => http-echo}/t/mixed.t | 0 .../t/request-body.t | 0 .../t/request-info.t | 0 .../{nginx-echo => http-echo}/t/sleep.t | 0 .../{nginx-echo => http-echo}/t/status.t | 0 .../t/subrequest-async.t | 0 .../{nginx-echo => http-echo}/t/subrequest.t | 0 .../{nginx-echo => http-echo}/t/unused.t | 0 .../{nginx-echo => http-echo}/util/build.sh | 0 .../{nginx-echo => http-echo}/util/releng | 0 .../util/wiki2pod.pl | 0 .../valgrind.suppress | 0 .../CHANGELOG.md | 0 .../HACKING.md | 0 .../LICENSE | 0 .../README.rst | 0 .../config | 0 .../nginx-0.6-support.patch | 0 .../ngx_http_fancyindex_module.c | 0 .../t/00-build-artifacts.test | 0 .../t/01-smoke-hasindex.test | 0 .../t/02-smoke-indexisfancy.test | 0 .../t/build-and-run | 0 .../t/has-index.test | 0 .../t/has-index/index.html | 0 .../t/nginx.conf | 0 .../t/preamble | 0 .../{ngx-fancyindex => http-fancyindex}/t/run | 0 .../template.awk | 0 .../template.h | 0 .../template.html | 0 .../README.markdown | 0 .../config | 0 .../src/ddebug.h | 0 .../src/ngx_http_headers_more_filter_module.c | 0 .../src/ngx_http_headers_more_filter_module.h | 0 .../src/ngx_http_headers_more_headers_in.c | 0 .../src/ngx_http_headers_more_headers_in.h | 0 .../src/ngx_http_headers_more_headers_out.c | 0 .../src/ngx_http_headers_more_headers_out.h | 0 .../src/ngx_http_headers_more_util.c | 0 .../src/ngx_http_headers_more_util.h | 0 .../t/bug.t | 0 .../t/builtin.t | 0 .../t/eval.t | 0 .../t/input-conn.t | 0 .../t/input-cookie.t | 0 .../t/input-ua.t | 0 .../t/input.t | 0 .../t/phase.t | 0 .../t/sanity.t | 0 .../t/subrequest.t | 0 .../t/unused.t | 0 .../t/vars.t | 0 .../util/build.sh | 0 .../valgrind.suppress | 0 .../{nginx-lua => http-lua}/README.markdown | 0 debian/modules/{nginx-lua => http-lua}/config | 0 .../doc/HttpLuaModule.wiki | 0 .../dtrace/ngx_lua_provider.d | 0 .../misc/recv-until-pm/Makefile | 0 .../misc/recv-until-pm/lib/RecvUntil.pm | 0 .../misc/recv-until-pm/t/sanity.t | 0 .../src/api/ngx_http_lua_api.h | 0 .../{nginx-lua => http-lua}/src/ddebug.h | 0 .../src/ngx_http_lua_accessby.c | 0 .../src/ngx_http_lua_accessby.h | 0 .../src/ngx_http_lua_api.c | 0 .../src/ngx_http_lua_args.c | 0 .../src/ngx_http_lua_args.h | 0 .../src/ngx_http_lua_balancer.c | 0 .../src/ngx_http_lua_balancer.h | 0 .../src/ngx_http_lua_bodyfilterby.c | 0 .../src/ngx_http_lua_bodyfilterby.h | 0 .../src/ngx_http_lua_cache.c | 0 .../src/ngx_http_lua_cache.h | 0 .../src/ngx_http_lua_capturefilter.c | 0 .../src/ngx_http_lua_capturefilter.h | 0 .../src/ngx_http_lua_clfactory.c | 0 .../src/ngx_http_lua_clfactory.h | 0 .../src/ngx_http_lua_common.h | 0 .../src/ngx_http_lua_config.c | 0 .../src/ngx_http_lua_config.h | 0 .../src/ngx_http_lua_consts.c | 0 .../src/ngx_http_lua_consts.h | 0 .../src/ngx_http_lua_contentby.c | 0 .../src/ngx_http_lua_contentby.h | 0 .../src/ngx_http_lua_control.c | 0 .../src/ngx_http_lua_control.h | 0 .../src/ngx_http_lua_coroutine.c | 0 .../src/ngx_http_lua_coroutine.h | 0 .../src/ngx_http_lua_ctx.c | 0 .../src/ngx_http_lua_ctx.h | 0 .../src/ngx_http_lua_directive.c | 0 .../src/ngx_http_lua_directive.h | 0 .../src/ngx_http_lua_exception.c | 0 .../src/ngx_http_lua_exception.h | 0 .../src/ngx_http_lua_headerfilterby.c | 0 .../src/ngx_http_lua_headerfilterby.h | 0 .../src/ngx_http_lua_headers.c | 0 .../src/ngx_http_lua_headers.h | 0 .../src/ngx_http_lua_headers_in.c | 0 .../src/ngx_http_lua_headers_in.h | 0 .../src/ngx_http_lua_headers_out.c | 0 .../src/ngx_http_lua_headers_out.h | 0 .../src/ngx_http_lua_initby.c | 0 .../src/ngx_http_lua_initby.h | 0 .../src/ngx_http_lua_initworkerby.c | 0 .../src/ngx_http_lua_initworkerby.h | 0 .../src/ngx_http_lua_lex.c | 0 .../src/ngx_http_lua_lex.h | 0 .../src/ngx_http_lua_log.c | 0 .../src/ngx_http_lua_log.h | 0 .../src/ngx_http_lua_log_ringbuf.c | 0 .../src/ngx_http_lua_log_ringbuf.h | 0 .../src/ngx_http_lua_logby.c | 0 .../src/ngx_http_lua_logby.h | 0 .../src/ngx_http_lua_misc.c | 0 .../src/ngx_http_lua_misc.h | 0 .../src/ngx_http_lua_module.c | 0 .../src/ngx_http_lua_ndk.c | 0 .../src/ngx_http_lua_ndk.h | 0 .../src/ngx_http_lua_output.c | 0 .../src/ngx_http_lua_output.h | 0 .../src/ngx_http_lua_pcrefix.c | 0 .../src/ngx_http_lua_pcrefix.h | 0 .../src/ngx_http_lua_phase.c | 0 .../src/ngx_http_lua_phase.h | 0 .../src/ngx_http_lua_probe.h | 0 .../src/ngx_http_lua_regex.c | 0 .../src/ngx_http_lua_regex.h | 0 .../src/ngx_http_lua_req_body.c | 0 .../src/ngx_http_lua_req_body.h | 0 .../src/ngx_http_lua_req_method.c | 0 .../src/ngx_http_lua_req_method.h | 0 .../src/ngx_http_lua_rewriteby.c | 0 .../src/ngx_http_lua_rewriteby.h | 0 .../src/ngx_http_lua_script.c | 0 .../src/ngx_http_lua_script.h | 0 .../src/ngx_http_lua_semaphore.c | 0 .../src/ngx_http_lua_semaphore.h | 0 .../src/ngx_http_lua_setby.c | 0 .../src/ngx_http_lua_setby.h | 0 .../src/ngx_http_lua_shdict.c | 0 .../src/ngx_http_lua_shdict.h | 0 .../src/ngx_http_lua_sleep.c | 0 .../src/ngx_http_lua_sleep.h | 0 .../src/ngx_http_lua_socket_tcp.c | 0 .../src/ngx_http_lua_socket_tcp.h | 0 .../src/ngx_http_lua_socket_udp.c | 0 .../src/ngx_http_lua_socket_udp.h | 0 .../src/ngx_http_lua_ssl.c | 0 .../src/ngx_http_lua_ssl.h | 0 .../src/ngx_http_lua_ssl_certby.c | 0 .../src/ngx_http_lua_ssl_certby.h | 0 .../src/ngx_http_lua_ssl_ocsp.c | 0 .../src/ngx_http_lua_ssl_session_fetchby.c | 0 .../src/ngx_http_lua_ssl_session_fetchby.h | 0 .../src/ngx_http_lua_ssl_session_storeby.c | 0 .../src/ngx_http_lua_ssl_session_storeby.h | 0 .../src/ngx_http_lua_string.c | 0 .../src/ngx_http_lua_string.h | 0 .../src/ngx_http_lua_subrequest.c | 0 .../src/ngx_http_lua_subrequest.h | 0 .../src/ngx_http_lua_time.c | 0 .../src/ngx_http_lua_time.h | 0 .../src/ngx_http_lua_timer.c | 0 .../src/ngx_http_lua_timer.h | 0 .../src/ngx_http_lua_uri.c | 0 .../src/ngx_http_lua_uri.h | 0 .../src/ngx_http_lua_uthread.c | 0 .../src/ngx_http_lua_uthread.h | 0 .../src/ngx_http_lua_util.c | 0 .../src/ngx_http_lua_util.h | 0 .../src/ngx_http_lua_variable.c | 0 .../src/ngx_http_lua_variable.h | 0 .../src/ngx_http_lua_worker.c | 0 .../src/ngx_http_lua_worker.h | 0 .../{nginx-lua => http-lua}/t/.gitignore | 0 .../{nginx-lua => http-lua}/t/000--init.t | 0 .../{nginx-lua => http-lua}/t/000-sanity.t | 0 .../{nginx-lua => http-lua}/t/001-set.t | 0 .../{nginx-lua => http-lua}/t/002-content.t | 0 .../{nginx-lua => http-lua}/t/003-errors.t | 0 .../{nginx-lua => http-lua}/t/004-require.t | 0 .../{nginx-lua => http-lua}/t/005-exit.t | 0 .../{nginx-lua => http-lua}/t/006-escape.t | 0 .../{nginx-lua => http-lua}/t/007-md5.t | 0 .../{nginx-lua => http-lua}/t/008-today.t | 0 .../{nginx-lua => http-lua}/t/009-log.t | 0 .../t/010-request_body.t | 0 .../{nginx-lua => http-lua}/t/011-md5_bin.t | 0 .../{nginx-lua => http-lua}/t/012-now.t | 0 .../{nginx-lua => http-lua}/t/013-base64.t | 0 .../{nginx-lua => http-lua}/t/014-bugs.t | 0 .../{nginx-lua => http-lua}/t/015-status.t | 0 .../t/016-resp-header.t | 0 .../{nginx-lua => http-lua}/t/017-exec.t | 0 .../{nginx-lua => http-lua}/t/018-ndk.t | 0 .../{nginx-lua => http-lua}/t/019-const.t | 0 .../t/020-subrequest.t | 0 .../t/021-cookie-time.t | 0 .../{nginx-lua => http-lua}/t/022-redirect.t | 0 .../t/023-rewrite/client-abort.t | 0 .../t/023-rewrite/exec.t | 0 .../t/023-rewrite/exit.t | 0 .../t/023-rewrite/mixed.t | 0 .../t/023-rewrite/multi-capture.t | 0 .../t/023-rewrite/on-abort.t | 0 .../t/023-rewrite/redirect.t | 0 .../t/023-rewrite/req-body.t | 0 .../t/023-rewrite/req-socket.t | 0 .../t/023-rewrite/request_body.t | 0 .../t/023-rewrite/sanity.t | 0 .../t/023-rewrite/sleep.t | 0 .../t/023-rewrite/socket-keepalive.t | 0 .../t/023-rewrite/subrequest.t | 0 .../t/023-rewrite/tcp-socket-timeout.t | 0 .../t/023-rewrite/tcp-socket.t | 0 .../t/023-rewrite/unix-socket.t | 0 .../t/023-rewrite/uthread-exec.t | 0 .../t/023-rewrite/uthread-exit.t | 0 .../t/023-rewrite/uthread-redirect.t | 0 .../t/023-rewrite/uthread-spawn.t | 0 .../t/024-access/auth.t | 0 .../t/024-access/client-abort.t | 0 .../t/024-access/exec.t | 0 .../t/024-access/exit.t | 0 .../t/024-access/mixed.t | 0 .../t/024-access/multi-capture.t | 0 .../t/024-access/on-abort.t | 0 .../t/024-access/redirect.t | 0 .../t/024-access/req-body.t | 0 .../t/024-access/request_body.t | 0 .../t/024-access/sanity.t | 0 .../t/024-access/satisfy.t | 0 .../t/024-access/sleep.t | 0 .../t/024-access/subrequest.t | 0 .../t/024-access/uthread-exec.t | 0 .../t/024-access/uthread-exit.t | 0 .../t/024-access/uthread-redirect.t | 0 .../t/024-access/uthread-spawn.t | 0 .../{nginx-lua => http-lua}/t/025-codecache.t | 0 .../{nginx-lua => http-lua}/t/026-mysql.t | 0 .../t/027-multi-capture.t | 0 .../t/028-req-header.t | 0 .../{nginx-lua => http-lua}/t/029-http-time.t | 0 .../{nginx-lua => http-lua}/t/030-uri-args.t | 0 .../{nginx-lua => http-lua}/t/031-post-args.t | 0 .../{nginx-lua => http-lua}/t/032-iolist.t | 0 .../{nginx-lua => http-lua}/t/033-ctx.t | 0 .../{nginx-lua => http-lua}/t/034-match.t | 0 .../{nginx-lua => http-lua}/t/035-gmatch.t | 0 .../{nginx-lua => http-lua}/t/036-sub.t | 0 .../{nginx-lua => http-lua}/t/037-gsub.t | 0 .../{nginx-lua => http-lua}/t/038-match-o.t | 0 .../{nginx-lua => http-lua}/t/039-sub-o.t | 0 .../{nginx-lua => http-lua}/t/040-gsub-o.t | 0 .../t/041-header-filter.t | 0 .../{nginx-lua => http-lua}/t/042-crc32.t | 0 .../{nginx-lua => http-lua}/t/043-shdict.t | 0 .../{nginx-lua => http-lua}/t/044-req-body.t | 0 .../{nginx-lua => http-lua}/t/045-ngx-var.t | 0 .../{nginx-lua => http-lua}/t/046-hmac.t | 0 .../{nginx-lua => http-lua}/t/047-match-jit.t | 0 .../{nginx-lua => http-lua}/t/048-match-dfa.t | 0 .../t/049-gmatch-jit.t | 0 .../t/050-gmatch-dfa.t | 0 .../{nginx-lua => http-lua}/t/051-sub-jit.t | 0 .../{nginx-lua => http-lua}/t/052-sub-dfa.t | 0 .../{nginx-lua => http-lua}/t/053-gsub-jit.t | 0 .../{nginx-lua => http-lua}/t/054-gsub-dfa.t | 0 .../t/055-subreq-vars.t | 0 .../{nginx-lua => http-lua}/t/056-flush.t | 0 .../t/057-flush-timeout.t | 0 .../t/058-tcp-socket.t | 0 .../t/059-unix-socket.t | 0 .../t/060-lua-memcached.t | 0 .../{nginx-lua => http-lua}/t/061-lua-redis.t | 0 .../{nginx-lua => http-lua}/t/062-count.t | 0 .../{nginx-lua => http-lua}/t/063-abort.t | 0 .../{nginx-lua => http-lua}/t/064-pcall.t | 0 .../t/065-tcp-socket-timeout.t | 0 .../t/066-socket-receiveuntil.t | 0 .../t/067-req-socket.t | 0 .../t/068-socket-keepalive.t | 0 .../{nginx-lua => http-lua}/t/069-null.t | 0 .../{nginx-lua => http-lua}/t/070-sha1.t | 0 .../t/071-idle-socket.t | 0 .../t/072-conditional-get.t | 0 .../{nginx-lua => http-lua}/t/073-backtrace.t | 0 .../t/074-prefix-var.t | 0 .../{nginx-lua => http-lua}/t/075-logby.t | 0 .../t/076-no-postpone.t | 0 .../{nginx-lua => http-lua}/t/077-sleep.t | 0 .../{nginx-lua => http-lua}/t/078-hup-vars.t | 0 .../t/079-unused-directives.t | 0 .../t/080-hup-shdict.t | 0 .../{nginx-lua => http-lua}/t/081-bytecode.t | 0 .../t/082-body-filter.t | 0 .../t/083-bad-sock-self.t | 0 .../t/084-inclusive-receiveuntil.t | 0 .../{nginx-lua => http-lua}/t/085-if.t | 0 .../{nginx-lua => http-lua}/t/086-init-by.t | 0 .../t/087-udp-socket.t | 0 .../t/088-req-method.t | 0 .../{nginx-lua => http-lua}/t/089-phase.t | 0 .../t/090-log-socket-errors.t | 0 .../{nginx-lua => http-lua}/t/091-coroutine.t | 0 .../{nginx-lua => http-lua}/t/092-eof.t | 0 .../t/093-uthread-spawn.t | 0 .../t/094-uthread-exit.t | 0 .../t/095-uthread-exec.t | 0 .../t/096-uthread-redirect.t | 0 .../t/097-uthread-rewrite.t | 0 .../t/098-uthread-wait.t | 0 .../{nginx-lua => http-lua}/t/099-c-api.t | 0 .../t/100-client-abort.t | 0 .../{nginx-lua => http-lua}/t/101-on-abort.t | 0 .../t/102-req-start-time.t | 0 .../t/103-req-http-ver.t | 0 .../t/104-req-raw-header.t | 0 .../{nginx-lua => http-lua}/t/105-pressure.t | 0 .../{nginx-lua => http-lua}/t/106-timer.t | 0 .../t/107-timer-errors.t | 0 .../t/108-timer-safe.t | 0 .../{nginx-lua => http-lua}/t/109-timer-hup.t | 0 .../{nginx-lua => http-lua}/t/110-etag.t | 0 .../t/111-req-header-ua.t | 0 .../t/112-req-header-conn.t | 0 .../t/113-req-header-cookie.t | 0 .../{nginx-lua => http-lua}/t/114-config.t | 0 .../t/115-quote-sql-str.t | 0 .../t/116-raw-req-socket.t | 0 .../t/117-raw-req-socket-timeout.t | 0 .../t/118-use-default-type.t | 0 .../t/119-config-prefix.t | 0 .../{nginx-lua => http-lua}/t/120-re-find.t | 0 .../{nginx-lua => http-lua}/t/121-version.t | 0 .../{nginx-lua => http-lua}/t/122-worker.t | 0 .../{nginx-lua => http-lua}/t/123-lua-path.t | 0 .../t/124-init-worker.t | 0 .../t/125-configure-args.t | 0 .../t/126-shdict-frag.t | 0 .../t/127-uthread-kill.t | 0 .../t/128-duplex-tcp-socket.t | 0 .../t/129-ssl-socket.t | 0 .../t/130-internal-api.t | 0 .../t/131-duplex-req-socket.t | 0 .../t/132-lua-blocks.t | 0 .../t/133-worker-count.t | 0 .../t/134-worker-count-5.t | 0 .../{nginx-lua => http-lua}/t/135-worker-id.t | 0 .../t/136-timer-counts.t | 0 .../{nginx-lua => http-lua}/t/137-req-misc.t | 0 .../{nginx-lua => http-lua}/t/138-balancer.t | 0 .../t/139-ssl-cert-by.t | 0 .../{nginx-lua => http-lua}/t/140-ssl-c-api.t | 0 .../{nginx-lua => http-lua}/t/141-luajit.t | 0 .../t/142-ssl-session-store.t | 0 .../t/143-ssl-session-fetch.t | 0 .../t/144-shdict-incr-init.t | 0 .../t/145-shdict-list.t | 0 .../t/146-malloc-trim.t | 0 .../t/147-tcp-socket-timeouts.t | 0 .../t/148-fake-shm-zone.t | 0 .../t/149-hup-fake-shm-zone.t | 0 .../t/150-fake-delayed-load.t | 0 .../t/151-initby-hup.t | 0 .../t/152-timer-every.t | 0 .../t/153-semaphore-hup.t | 0 .../{nginx-lua => http-lua}/t/154-semaphore.t | 0 .../{nginx-lua => http-lua}/t/StapThread.pm | 0 .../t/cert/comodo-ca.crt | 0 .../t/cert/equifax.crt | 0 .../{nginx-lua => http-lua}/t/cert/test.crl | 0 .../{nginx-lua => http-lua}/t/cert/test.crt | 0 .../{nginx-lua => http-lua}/t/cert/test.key | 0 .../{nginx-lua => http-lua}/t/cert/test2.crt | 0 .../{nginx-lua => http-lua}/t/cert/test2.key | 0 .../t/cert/test_ecdsa.crt | 0 .../t/cert/test_ecdsa.key | 0 .../t/data/fake-delayed-load-module/config | 0 .../ngx_http_lua_fake_delayed_load_module.c | 0 .../t/data/fake-module/config | 0 .../t/data/fake-module/ngx_http_fake_module.c | 0 .../t/data/fake-shm-module/config | 0 .../ngx_http_lua_fake_shm_module.c | 0 .../{nginx-lua => http-lua}/t/lib/CRC32.lua | 0 .../t/lib/Memcached.lua | 0 .../{nginx-lua => http-lua}/t/lib/Redis.lua | 0 .../{nginx-lua => http-lua}/t/lib/ljson.lua | 0 .../tapset/ngx_lua.stp | 0 .../{nginx-lua => http-lua}/util/build.sh | 0 .../{nginx-lua => http-lua}/util/fix-comments | 0 .../{nginx-lua => http-lua}/util/gen-lexer-c | 0 .../{nginx-lua => http-lua}/util/ngx-links | 0 .../{nginx-lua => http-lua}/util/releng | 0 .../{nginx-lua => http-lua}/util/retab | 0 .../{nginx-lua => http-lua}/util/revim | 0 .../{nginx-lua => http-lua}/util/run_test.sh | 0 .../util/update-readme.sh | 0 .../{nginx-lua => http-lua}/valgrind.suppress | 0 .../LICENSE | 0 .../README.md | 0 .../README_AUTO_LIB | 0 .../{nginx-development-kit => http-ndk}/TODO | 0 .../auto/actions/array | 0 .../auto/actions/palloc | 0 .../auto/build | 0 .../auto/data/action_replacements | 0 .../auto/data/action_types | 0 .../auto/data/conf_args | 0 .../auto/data/conf_locs | 0 .../auto/data/conf_macros | 0 .../auto/data/contexts | 0 .../auto/data/header_files | 0 .../auto/data/headers | 0 .../auto/data/module_dependencies | 0 .../auto/data/modules_optional | 0 .../auto/data/prefixes | 0 .../auto/src/array.h | 0 .../auto/src/conf_cmd_basic.h | 0 .../auto/src/conf_merge.h | 0 .../auto/src/palloc.h | 0 .../auto/text/autogen | 0 .../config | 0 .../docs/core/action_macros | 0 .../docs/core/conf_cmds | 0 .../docs/modules/set_var | 0 .../docs/patches/more_logging_info | 0 .../docs/upstream/list | 0 .../examples/README | 0 .../examples/http/set_var/config | 0 .../ngx_http_set_var_examples_module.c | 0 .../ngx_auto_lib_core | 0 .../notes/CHANGES | 0 .../notes/LICENSE | 0 .../objs/ndk_array.h | 0 .../objs/ndk_conf_cmd_basic.h | 0 .../objs/ndk_conf_cmd_extra.h | 0 .../objs/ndk_conf_merge.h | 0 .../objs/ndk_config.c | 0 .../objs/ndk_config.h | 0 .../objs/ndk_includes.h | 0 .../objs/ndk_palloc.h | 0 .../patches/auto_config | 0 .../patches/expose_rewrite_functions | 0 .../patches/rewrite_phase_handler | 0 .../src/hash/md5.h | 0 .../src/hash/murmurhash2.c | 0 .../src/hash/sha.h | 0 .../src/ndk.c | 0 .../src/ndk.h | 0 .../src/ndk_buf.c | 0 .../src/ndk_buf.h | 0 .../src/ndk_complex_path.c | 0 .../src/ndk_complex_path.h | 0 .../src/ndk_complex_value.c | 0 .../src/ndk_complex_value.h | 0 .../src/ndk_conf_file.c | 0 .../src/ndk_conf_file.h | 0 .../src/ndk_debug.c | 0 .../src/ndk_debug.h | 0 .../src/ndk_encoding.c | 0 .../src/ndk_encoding.h | 0 .../src/ndk_hash.c | 0 .../src/ndk_hash.h | 0 .../src/ndk_http.c | 0 .../src/ndk_http.h | 0 .../src/ndk_http_headers.h | 0 .../src/ndk_log.c | 0 .../src/ndk_log.h | 0 .../src/ndk_parse.h | 0 .../src/ndk_path.c | 0 .../src/ndk_path.h | 0 .../src/ndk_process.c | 0 .../src/ndk_process.h | 0 .../src/ndk_regex.c | 0 .../src/ndk_regex.h | 0 .../src/ndk_rewrite.c | 0 .../src/ndk_rewrite.h | 0 .../src/ndk_set_var.c | 0 .../src/ndk_set_var.h | 0 .../src/ndk_string.c | 0 .../src/ndk_string.h | 0 .../src/ndk_string_util.h | 0 .../src/ndk_upstream_list.c | 0 .../src/ndk_upstream_list.h | 0 .../src/ndk_uri.c | 0 .../src/ndk_uri.h | 0 .../CHANGES | 0 .../README | 0 .../config | 0 .../doc/README.google_code_home_page.wiki | 0 .../doc/README.html | 0 .../doc/README.wiki | 0 .../ngx_http_subs_filter_module.c | 0 .../test/README | 0 .../test/inc/Module/AutoInstall.pm | 0 .../test/inc/Module/Install.pm | 0 .../test/inc/Module/Install/AutoInstall.pm | 0 .../test/inc/Module/Install/Base.pm | 0 .../test/inc/Module/Install/Can.pm | 0 .../test/inc/Module/Install/Fetch.pm | 0 .../test/inc/Module/Install/Include.pm | 0 .../test/inc/Module/Install/Makefile.pm | 0 .../test/inc/Module/Install/Metadata.pm | 0 .../test/inc/Module/Install/TestBase.pm | 0 .../test/inc/Module/Install/Win32.pm | 0 .../test/inc/Module/Install/WriteAll.pm | 0 .../test/inc/Spiffy.pm | 0 .../test/inc/Test/Base.pm | 0 .../test/inc/Test/Base/Filter.pm | 0 .../test/inc/Test/Builder.pm | 0 .../test/inc/Test/Builder/Module.pm | 0 .../test/inc/Test/More.pm | 0 .../test/lib/Test/Nginx.pm | 0 .../test/lib/Test/Nginx/LWP.pm | 0 .../test/lib/Test/Nginx/Socket.pm | 0 .../test/lib/Test/Nginx/Util.pm | 0 .../test/t/subs.t | 0 .../test/t/subs_capture.t | 0 .../test/t/subs_fix_string.t | 0 .../test/t/subs_regex.t | 0 .../test/t/subs_types.t | 0 .../test/test.sh | 0 .../util/update-readme.sh | 0 .../util/wiki2google_code_homepage.pl | 0 .../util/wiki2pod.pl | 0 .../CHANGES | 0 .../LICENSE | 0 .../Makefile | 0 .../README | 0 .../config | 0 .../ngx_http_uploadprogress_module.c | 0 .../test/client.sh | 0 .../test/stress.sh | 0 .../.gdbinit | 0 .../README | 0 .../config | 0 .../ngx_http_upstream_fair_module.c | 0 .../dynamic-module.patch | 0 .../segfault-1.11.6.patch | 0 .../series | 0 .../dynamic-module.patch | 0 .../series | 0 .../build-nginx-1.11.11.patch | 0 .../patches/{nginx-echo => http-echo}/series | 0 .../discover-luajit-2.1.patch | 0 .../openssl-1.1.0.patch | 0 .../patches/{nginx-lua => http-lua}/series | 0 .../dynamic-module.patch | 0 .../series | 0 .../drop-default-port.patch | 0 .../dynamic-module.patch | 0 .../openssl-1.1.0.patch | 0 .../series | 0 debian/modules/{nginx-rtmp => rtmp}/AUTHORS | 0 debian/modules/{nginx-rtmp => rtmp}/LICENSE | 0 debian/modules/{nginx-rtmp => rtmp}/README.md | 0 debian/modules/{nginx-rtmp => rtmp}/config | 0 .../dash/ngx_rtmp_dash_module.c | 0 .../{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.c | 0 .../{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.h | 0 .../{nginx-rtmp => rtmp}/doc/README.md | 0 .../hls/ngx_rtmp_hls_module.c | 0 .../hls/ngx_rtmp_mpegts.c | 0 .../hls/ngx_rtmp_mpegts.h | 0 .../modules/{nginx-rtmp => rtmp}/ngx_rtmp.c | 0 .../modules/{nginx-rtmp => rtmp}/ngx_rtmp.h | 0 .../ngx_rtmp_access_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_amf.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_amf.h | 0 .../ngx_rtmp_auto_push_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bitop.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_bitop.h | 0 .../ngx_rtmp_cmd_module.c | 0 .../ngx_rtmp_cmd_module.h | 0 .../ngx_rtmp_codec_module.c | 0 .../ngx_rtmp_codec_module.h | 0 .../ngx_rtmp_control_module.c | 0 .../ngx_rtmp_core_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_eval.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_eval.h | 0 .../ngx_rtmp_exec_module.c | 0 .../ngx_rtmp_flv_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_handler.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_handshake.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_init.c | 0 .../ngx_rtmp_limit_module.c | 0 .../ngx_rtmp_live_module.c | 0 .../ngx_rtmp_live_module.h | 0 .../ngx_rtmp_log_module.c | 0 .../ngx_rtmp_mp4_module.c | 0 .../ngx_rtmp_netcall_module.c | 0 .../ngx_rtmp_netcall_module.h | 0 .../ngx_rtmp_notify_module.c | 0 .../ngx_rtmp_play_module.c | 0 .../ngx_rtmp_play_module.h | 0 .../ngx_rtmp_proxy_protocol.c | 0 .../ngx_rtmp_proxy_protocol.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_receive.c | 0 .../ngx_rtmp_record_module.c | 0 .../ngx_rtmp_record_module.h | 0 .../ngx_rtmp_relay_module.c | 0 .../ngx_rtmp_relay_module.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_send.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_shared.c | 0 .../ngx_rtmp_stat_module.c | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_streams.h | 0 .../{nginx-rtmp => rtmp}/ngx_rtmp_version.h | 0 debian/modules/{nginx-rtmp => rtmp}/stat.xsl | 0 debian/rules | 36 +++++++++---------- 679 files changed, 32 insertions(+), 32 deletions(-) rename debian/modules/{nginx-auth-pam => http-auth-pam}/ChangeLog (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/LICENSE (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/README.md (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/VERSION (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/config (100%) rename debian/modules/{nginx-auth-pam => http-auth-pam}/ngx_http_auth_pam_module.c (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/CHANGES (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/LICENSE (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/README.md (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/TODO.md (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/config (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/ngx_cache_purge_module.c (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy1.t (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy1_vars.t (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy2.t (100%) rename debian/modules/{nginx-cache-purge => http-cache-purge}/t/proxy2_vars.t (100%) rename debian/modules/{nginx-dav-ext-module => http-dav-ext}/README (100%) rename debian/modules/{nginx-dav-ext-module => http-dav-ext}/config (100%) rename debian/modules/{nginx-dav-ext-module => http-dav-ext}/ngx_http_dav_ext_module.c (100%) rename debian/modules/{nginx-echo => http-echo}/LICENSE (100%) rename debian/modules/{nginx-echo => http-echo}/README.markdown (100%) rename debian/modules/{nginx-echo => http-echo}/config (100%) rename debian/modules/{nginx-echo => http-echo}/src/ddebug.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_echo.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_echo.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_filter.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_filter.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_foreach.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_foreach.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_handler.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_handler.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_location.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_location.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_module.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_module.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_request_info.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_request_info.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_sleep.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_sleep.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_subrequest.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_subrequest.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_timer.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_timer.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_util.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_util.h (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_var.c (100%) rename debian/modules/{nginx-echo => http-echo}/src/ngx_http_echo_var.h (100%) rename debian/modules/{nginx-echo => http-echo}/t/abort-parent.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/blocking-sleep.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-after-body.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-before-body.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-duplicate.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo-timer.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/echo.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/exec.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/filter-used.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/foreach-split.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/gzip.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/if.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/incr.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/location-async.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/location.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/mixed.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/request-body.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/request-info.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/sleep.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/status.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/subrequest-async.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/subrequest.t (100%) rename debian/modules/{nginx-echo => http-echo}/t/unused.t (100%) rename debian/modules/{nginx-echo => http-echo}/util/build.sh (100%) rename debian/modules/{nginx-echo => http-echo}/util/releng (100%) rename debian/modules/{nginx-echo => http-echo}/util/wiki2pod.pl (100%) rename debian/modules/{nginx-echo => http-echo}/valgrind.suppress (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/CHANGELOG.md (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/HACKING.md (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/LICENSE (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/README.rst (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/config (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/nginx-0.6-support.patch (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/ngx_http_fancyindex_module.c (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/00-build-artifacts.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/01-smoke-hasindex.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/02-smoke-indexisfancy.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/build-and-run (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/has-index.test (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/has-index/index.html (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/nginx.conf (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/preamble (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/t/run (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/template.awk (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/template.h (100%) rename debian/modules/{ngx-fancyindex => http-fancyindex}/template.html (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/README.markdown (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/config (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ddebug.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_filter_module.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_filter_module.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_in.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_in.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_out.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_headers_out.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_util.c (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/src/ngx_http_headers_more_util.h (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/bug.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/builtin.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/eval.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input-conn.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input-cookie.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input-ua.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/input.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/phase.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/sanity.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/subrequest.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/unused.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/t/vars.t (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/util/build.sh (100%) rename debian/modules/{headers-more-nginx-module => http-headers-more-filter}/valgrind.suppress (100%) rename debian/modules/{nginx-lua => http-lua}/README.markdown (100%) rename debian/modules/{nginx-lua => http-lua}/config (100%) rename debian/modules/{nginx-lua => http-lua}/doc/HttpLuaModule.wiki (100%) rename debian/modules/{nginx-lua => http-lua}/dtrace/ngx_lua_provider.d (100%) rename debian/modules/{nginx-lua => http-lua}/misc/recv-until-pm/Makefile (100%) rename debian/modules/{nginx-lua => http-lua}/misc/recv-until-pm/lib/RecvUntil.pm (100%) rename debian/modules/{nginx-lua => http-lua}/misc/recv-until-pm/t/sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/src/api/ngx_http_lua_api.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ddebug.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_accessby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_accessby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_api.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_args.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_args.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_balancer.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_balancer.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_bodyfilterby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_bodyfilterby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_cache.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_cache.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_capturefilter.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_capturefilter.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_clfactory.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_clfactory.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_common.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_config.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_config.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_consts.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_consts.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_contentby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_contentby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_control.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_control.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_coroutine.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_coroutine.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ctx.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ctx.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_directive.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_directive.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_exception.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_exception.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headerfilterby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headerfilterby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_in.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_in.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_out.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_headers_out.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initworkerby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_initworkerby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_lex.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_lex.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log_ringbuf.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_log_ringbuf.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_logby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_logby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_misc.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_misc.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ndk.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ndk.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_output.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_output.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_pcrefix.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_pcrefix.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_phase.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_phase.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_probe.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_regex.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_regex.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_body.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_body.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_method.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_req_method.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_rewriteby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_rewriteby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_script.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_script.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_semaphore.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_semaphore.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_setby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_setby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_shdict.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_shdict.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_sleep.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_sleep.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_tcp.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_tcp.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_udp.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_socket_udp.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_certby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_certby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_ocsp.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_fetchby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_fetchby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_storeby.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_ssl_session_storeby.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_string.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_string.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_subrequest.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_subrequest.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_time.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_time.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_timer.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_timer.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uri.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uri.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uthread.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_uthread.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_util.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_util.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_variable.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_variable.h (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_worker.c (100%) rename debian/modules/{nginx-lua => http-lua}/src/ngx_http_lua_worker.h (100%) rename debian/modules/{nginx-lua => http-lua}/t/.gitignore (100%) rename debian/modules/{nginx-lua => http-lua}/t/000--init.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/000-sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/001-set.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/002-content.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/003-errors.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/004-require.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/005-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/006-escape.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/007-md5.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/008-today.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/009-log.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/010-request_body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/011-md5_bin.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/012-now.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/013-base64.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/014-bugs.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/015-status.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/016-resp-header.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/017-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/018-ndk.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/019-const.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/020-subrequest.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/021-cookie-time.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/022-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/client-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/mixed.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/multi-capture.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/on-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/req-body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/request_body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/sleep.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/socket-keepalive.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/subrequest.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/tcp-socket-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/tcp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/unix-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/023-rewrite/uthread-spawn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/auth.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/client-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/mixed.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/multi-capture.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/on-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/req-body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/request_body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/sanity.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/satisfy.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/sleep.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/subrequest.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/024-access/uthread-spawn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/025-codecache.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/026-mysql.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/027-multi-capture.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/028-req-header.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/029-http-time.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/030-uri-args.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/031-post-args.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/032-iolist.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/033-ctx.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/034-match.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/035-gmatch.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/036-sub.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/037-gsub.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/038-match-o.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/039-sub-o.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/040-gsub-o.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/041-header-filter.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/042-crc32.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/043-shdict.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/044-req-body.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/045-ngx-var.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/046-hmac.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/047-match-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/048-match-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/049-gmatch-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/050-gmatch-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/051-sub-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/052-sub-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/053-gsub-jit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/054-gsub-dfa.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/055-subreq-vars.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/056-flush.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/057-flush-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/058-tcp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/059-unix-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/060-lua-memcached.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/061-lua-redis.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/062-count.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/063-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/064-pcall.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/065-tcp-socket-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/066-socket-receiveuntil.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/067-req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/068-socket-keepalive.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/069-null.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/070-sha1.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/071-idle-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/072-conditional-get.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/073-backtrace.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/074-prefix-var.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/075-logby.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/076-no-postpone.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/077-sleep.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/078-hup-vars.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/079-unused-directives.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/080-hup-shdict.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/081-bytecode.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/082-body-filter.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/083-bad-sock-self.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/084-inclusive-receiveuntil.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/085-if.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/086-init-by.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/087-udp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/088-req-method.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/089-phase.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/090-log-socket-errors.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/091-coroutine.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/092-eof.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/093-uthread-spawn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/094-uthread-exit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/095-uthread-exec.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/096-uthread-redirect.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/097-uthread-rewrite.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/098-uthread-wait.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/099-c-api.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/100-client-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/101-on-abort.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/102-req-start-time.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/103-req-http-ver.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/104-req-raw-header.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/105-pressure.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/106-timer.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/107-timer-errors.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/108-timer-safe.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/109-timer-hup.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/110-etag.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/111-req-header-ua.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/112-req-header-conn.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/113-req-header-cookie.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/114-config.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/115-quote-sql-str.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/116-raw-req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/117-raw-req-socket-timeout.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/118-use-default-type.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/119-config-prefix.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/120-re-find.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/121-version.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/122-worker.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/123-lua-path.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/124-init-worker.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/125-configure-args.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/126-shdict-frag.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/127-uthread-kill.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/128-duplex-tcp-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/129-ssl-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/130-internal-api.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/131-duplex-req-socket.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/132-lua-blocks.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/133-worker-count.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/134-worker-count-5.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/135-worker-id.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/136-timer-counts.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/137-req-misc.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/138-balancer.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/139-ssl-cert-by.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/140-ssl-c-api.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/141-luajit.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/142-ssl-session-store.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/143-ssl-session-fetch.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/144-shdict-incr-init.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/145-shdict-list.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/146-malloc-trim.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/147-tcp-socket-timeouts.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/148-fake-shm-zone.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/149-hup-fake-shm-zone.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/150-fake-delayed-load.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/151-initby-hup.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/152-timer-every.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/153-semaphore-hup.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/154-semaphore.t (100%) rename debian/modules/{nginx-lua => http-lua}/t/StapThread.pm (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/comodo-ca.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/equifax.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test.crl (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test.key (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test2.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test2.key (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test_ecdsa.crt (100%) rename debian/modules/{nginx-lua => http-lua}/t/cert/test_ecdsa.key (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-delayed-load-module/config (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-module/config (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-module/ngx_http_fake_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-shm-module/config (100%) rename debian/modules/{nginx-lua => http-lua}/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/CRC32.lua (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/Memcached.lua (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/Redis.lua (100%) rename debian/modules/{nginx-lua => http-lua}/t/lib/ljson.lua (100%) rename debian/modules/{nginx-lua => http-lua}/tapset/ngx_lua.stp (100%) rename debian/modules/{nginx-lua => http-lua}/util/build.sh (100%) rename debian/modules/{nginx-lua => http-lua}/util/fix-comments (100%) rename debian/modules/{nginx-lua => http-lua}/util/gen-lexer-c (100%) rename debian/modules/{nginx-lua => http-lua}/util/ngx-links (100%) rename debian/modules/{nginx-lua => http-lua}/util/releng (100%) rename debian/modules/{nginx-lua => http-lua}/util/retab (100%) rename debian/modules/{nginx-lua => http-lua}/util/revim (100%) rename debian/modules/{nginx-lua => http-lua}/util/run_test.sh (100%) rename debian/modules/{nginx-lua => http-lua}/util/update-readme.sh (100%) rename debian/modules/{nginx-lua => http-lua}/valgrind.suppress (100%) rename debian/modules/{nginx-development-kit => http-ndk}/LICENSE (100%) rename debian/modules/{nginx-development-kit => http-ndk}/README.md (100%) rename debian/modules/{nginx-development-kit => http-ndk}/README_AUTO_LIB (100%) rename debian/modules/{nginx-development-kit => http-ndk}/TODO (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/actions/array (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/actions/palloc (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/build (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/action_replacements (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/action_types (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/conf_args (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/conf_locs (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/conf_macros (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/contexts (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/header_files (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/headers (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/module_dependencies (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/modules_optional (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/data/prefixes (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/array.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/conf_cmd_basic.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/conf_merge.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/src/palloc.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/auto/text/autogen (100%) rename debian/modules/{nginx-development-kit => http-ndk}/config (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/core/action_macros (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/core/conf_cmds (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/modules/set_var (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/patches/more_logging_info (100%) rename debian/modules/{nginx-development-kit => http-ndk}/docs/upstream/list (100%) rename debian/modules/{nginx-development-kit => http-ndk}/examples/README (100%) rename debian/modules/{nginx-development-kit => http-ndk}/examples/http/set_var/config (100%) rename debian/modules/{nginx-development-kit => http-ndk}/examples/http/set_var/ngx_http_set_var_examples_module.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/ngx_auto_lib_core (100%) rename debian/modules/{nginx-development-kit => http-ndk}/notes/CHANGES (100%) rename debian/modules/{nginx-development-kit => http-ndk}/notes/LICENSE (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_array.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_conf_cmd_basic.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_conf_cmd_extra.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_conf_merge.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_config.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_config.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_includes.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/objs/ndk_palloc.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/patches/auto_config (100%) rename debian/modules/{nginx-development-kit => http-ndk}/patches/expose_rewrite_functions (100%) rename debian/modules/{nginx-development-kit => http-ndk}/patches/rewrite_phase_handler (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/hash/md5.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/hash/murmurhash2.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/hash/sha.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_buf.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_buf.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_path.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_path.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_value.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_complex_value.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_conf_file.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_conf_file.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_debug.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_debug.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_encoding.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_encoding.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_hash.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_hash.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_http.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_http.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_http_headers.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_log.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_log.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_parse.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_path.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_path.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_process.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_process.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_regex.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_regex.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_rewrite.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_rewrite.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_set_var.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_set_var.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_string.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_string.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_string_util.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_upstream_list.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_upstream_list.h (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_uri.c (100%) rename debian/modules/{nginx-development-kit => http-ndk}/src/ndk_uri.h (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/CHANGES (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/README (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/config (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/doc/README.google_code_home_page.wiki (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/doc/README.html (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/doc/README.wiki (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/ngx_http_subs_filter_module.c (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/README (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/AutoInstall.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/AutoInstall.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Base.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Can.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Fetch.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Include.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Makefile.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Metadata.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/TestBase.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/Win32.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Module/Install/WriteAll.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Spiffy.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Base.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Base/Filter.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Builder.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/Builder/Module.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/inc/Test/More.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx/LWP.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx/Socket.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/lib/Test/Nginx/Util.pm (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_capture.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_fix_string.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_regex.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/t/subs_types.t (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/test/test.sh (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/util/update-readme.sh (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/util/wiki2google_code_homepage.pl (100%) rename debian/modules/{ngx_http_substitutions_filter_module => http-subs-filter}/util/wiki2pod.pl (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/CHANGES (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/LICENSE (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/Makefile (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/README (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/config (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/ngx_http_uploadprogress_module.c (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/test/client.sh (100%) rename debian/modules/{nginx-upload-progress => http-uploadprogress}/test/stress.sh (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/.gdbinit (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/README (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/config (100%) rename debian/modules/{nginx-upstream-fair => http-upstream-fair}/ngx_http_upstream_fair_module.c (100%) rename debian/modules/patches/{nginx-cache-purge => http-cache-purge}/dynamic-module.patch (100%) rename debian/modules/patches/{nginx-cache-purge => http-cache-purge}/segfault-1.11.6.patch (100%) rename debian/modules/patches/{nginx-cache-purge => http-cache-purge}/series (100%) rename debian/modules/patches/{nginx-dav-ext-module => http-dav-ext}/dynamic-module.patch (100%) rename debian/modules/patches/{nginx-dav-ext-module => http-dav-ext}/series (100%) rename debian/modules/patches/{nginx-echo => http-echo}/build-nginx-1.11.11.patch (100%) rename debian/modules/patches/{nginx-echo => http-echo}/series (100%) rename debian/modules/patches/{nginx-lua => http-lua}/discover-luajit-2.1.patch (100%) rename debian/modules/patches/{nginx-lua => http-lua}/openssl-1.1.0.patch (100%) rename debian/modules/patches/{nginx-lua => http-lua}/series (100%) rename debian/modules/patches/{ngx_http_substitutions_filter_module => http-subs-filter}/dynamic-module.patch (100%) rename debian/modules/patches/{ngx_http_substitutions_filter_module => http-subs-filter}/series (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/drop-default-port.patch (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/dynamic-module.patch (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/openssl-1.1.0.patch (100%) rename debian/modules/patches/{nginx-upstream-fair => http-upstream-fair}/series (100%) rename debian/modules/{nginx-rtmp => rtmp}/AUTHORS (100%) rename debian/modules/{nginx-rtmp => rtmp}/LICENSE (100%) rename debian/modules/{nginx-rtmp => rtmp}/README.md (100%) rename debian/modules/{nginx-rtmp => rtmp}/config (100%) rename debian/modules/{nginx-rtmp => rtmp}/dash/ngx_rtmp_dash_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/dash/ngx_rtmp_mp4.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/doc/README.md (100%) rename debian/modules/{nginx-rtmp => rtmp}/hls/ngx_rtmp_hls_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/hls/ngx_rtmp_mpegts.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/hls/ngx_rtmp_mpegts.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_access_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_amf.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_amf.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_auto_push_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bandwidth.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bitop.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_bitop.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_cmd_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_cmd_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_codec_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_codec_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_control_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_core_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_eval.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_eval.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_exec_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_flv_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_handler.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_handshake.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_init.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_limit_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_live_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_live_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_log_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_mp4_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_netcall_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_netcall_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_notify_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_play_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_play_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_proxy_protocol.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_proxy_protocol.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_receive.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_record_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_record_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_relay_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_relay_module.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_send.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_shared.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_stat_module.c (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_streams.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/ngx_rtmp_version.h (100%) rename debian/modules/{nginx-rtmp => rtmp}/stat.xsl (100%) diff --git a/debian/copyright b/debian/copyright index 3d1b4c5..7bba41c 100644 --- a/debian/copyright +++ b/debian/copyright @@ -37,35 +37,35 @@ Copyright: 2007-2009, Fabio Tranchitella 2013-2016, Christos Trochalakis License: BSD-2-clause -Files: debian/modules/headers-more-nginx-module/* +Files: debian/modules/http-headers-more-filter/* Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. Copyright (c) 2010-2013, Bernd Dorn Copyright (c) Igor Sysoev License: BSD-2-clause -Files: debian/modules/nginx-development-kit/* +Files: debian/modules/http-ndk/* Copyright: Marcus Clyne License: BSD-3-clause -Files: debian/modules/nginx-development-kit/src/hash/md5.h - debian/modules/nginx-development-kit/src/hash/sha.h +Files: debian/modules/http-ndk/src/hash/md5.h + debian/modules/http-ndk/src/hash/sha.h Copyright: Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) License: BSD-4-clause -Files: debian/modules/nginx-auth-pam/* +Files: debian/modules/http-auth-pam/* Copyright: 2008-2013, Sergio Talens Oliag License: BSD-2-clause -Files: debian/modules/nginx-echo/* +Files: debian/modules/http-echo/* Copyright: Copyright (c) 2009-2014, Yichun "agentzh" Zhang License: BSD-2-clause -Files: debian/modules/nginx-lua/* +Files: debian/modules/http-lua/* Copyright: Copyright (C) 2009-2014, by Xiaozhe Wang (chaoslawful) . Copyright (C) 2009-2014, by Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. License: BSD-2-clause -Files: debian/modules/nginx-upstream-fair/* +Files: debian/modules/http-upstream-fair/* Copyright: Copyright (c) 2007 Grzegorz Nosek Igor Sysoev License: BSD-2-clause @@ -85,29 +85,29 @@ Copyright: 2009-2011, Salvatore Sanfilippo Jan-Erik Rediger License: BSD-3-clause -Files: debian/modules/nginx-upload-progress/* +Files: debian/modules/http-uploadprogress/* Copyright: Brice Figureau 2002-2007, Igor Sysoev License: BSD-2-clause -Files: debian/modules/nginx-cache-purge/* +Files: debian/modules/http-cache-purge/* Copyright: 2009-2012, FRiCKLE , 2009-2012, Piotr Sikora License: BSD-2-clause -Files: debian/modules/nginx-dav-ext-module/* +Files: debian/modules/http-dav-ext/* Copyright: Arutyunyan Roman License: BSD-2-clause -Files: debian/modules/ngx-fancyindex/* +Files: debian/modules/http-fancyindex/* Copyright: Copyright (c) Adrian Perez License: BSD-2-clause -Files: debian/modules/ngx_http_substitutions_filter_module/* +Files: debian/modules/http-subs-filter/* Copyright: Copyright (C) 2014 by Weibin Yao License: BSD-2-clause -Files: debian/modules/nginx-rtmp/* +Files: debian/modules/rtmp/* Copyright: Copyright (C) 2012-2014, Roman Arutyunyan License: BSD-2-clause diff --git a/debian/modules/nginx-auth-pam/ChangeLog b/debian/modules/http-auth-pam/ChangeLog similarity index 100% rename from debian/modules/nginx-auth-pam/ChangeLog rename to debian/modules/http-auth-pam/ChangeLog diff --git a/debian/modules/nginx-auth-pam/LICENSE b/debian/modules/http-auth-pam/LICENSE similarity index 100% rename from debian/modules/nginx-auth-pam/LICENSE rename to debian/modules/http-auth-pam/LICENSE diff --git a/debian/modules/nginx-auth-pam/README.md b/debian/modules/http-auth-pam/README.md similarity index 100% rename from debian/modules/nginx-auth-pam/README.md rename to debian/modules/http-auth-pam/README.md diff --git a/debian/modules/nginx-auth-pam/VERSION b/debian/modules/http-auth-pam/VERSION similarity index 100% rename from debian/modules/nginx-auth-pam/VERSION rename to debian/modules/http-auth-pam/VERSION diff --git a/debian/modules/nginx-auth-pam/config b/debian/modules/http-auth-pam/config similarity index 100% rename from debian/modules/nginx-auth-pam/config rename to debian/modules/http-auth-pam/config diff --git a/debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c b/debian/modules/http-auth-pam/ngx_http_auth_pam_module.c similarity index 100% rename from debian/modules/nginx-auth-pam/ngx_http_auth_pam_module.c rename to debian/modules/http-auth-pam/ngx_http_auth_pam_module.c diff --git a/debian/modules/nginx-cache-purge/CHANGES b/debian/modules/http-cache-purge/CHANGES similarity index 100% rename from debian/modules/nginx-cache-purge/CHANGES rename to debian/modules/http-cache-purge/CHANGES diff --git a/debian/modules/nginx-cache-purge/LICENSE b/debian/modules/http-cache-purge/LICENSE similarity index 100% rename from debian/modules/nginx-cache-purge/LICENSE rename to debian/modules/http-cache-purge/LICENSE diff --git a/debian/modules/nginx-cache-purge/README.md b/debian/modules/http-cache-purge/README.md similarity index 100% rename from debian/modules/nginx-cache-purge/README.md rename to debian/modules/http-cache-purge/README.md diff --git a/debian/modules/nginx-cache-purge/TODO.md b/debian/modules/http-cache-purge/TODO.md similarity index 100% rename from debian/modules/nginx-cache-purge/TODO.md rename to debian/modules/http-cache-purge/TODO.md diff --git a/debian/modules/nginx-cache-purge/config b/debian/modules/http-cache-purge/config similarity index 100% rename from debian/modules/nginx-cache-purge/config rename to debian/modules/http-cache-purge/config diff --git a/debian/modules/nginx-cache-purge/ngx_cache_purge_module.c b/debian/modules/http-cache-purge/ngx_cache_purge_module.c similarity index 100% rename from debian/modules/nginx-cache-purge/ngx_cache_purge_module.c rename to debian/modules/http-cache-purge/ngx_cache_purge_module.c diff --git a/debian/modules/nginx-cache-purge/t/proxy1.t b/debian/modules/http-cache-purge/t/proxy1.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy1.t rename to debian/modules/http-cache-purge/t/proxy1.t diff --git a/debian/modules/nginx-cache-purge/t/proxy1_vars.t b/debian/modules/http-cache-purge/t/proxy1_vars.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy1_vars.t rename to debian/modules/http-cache-purge/t/proxy1_vars.t diff --git a/debian/modules/nginx-cache-purge/t/proxy2.t b/debian/modules/http-cache-purge/t/proxy2.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy2.t rename to debian/modules/http-cache-purge/t/proxy2.t diff --git a/debian/modules/nginx-cache-purge/t/proxy2_vars.t b/debian/modules/http-cache-purge/t/proxy2_vars.t similarity index 100% rename from debian/modules/nginx-cache-purge/t/proxy2_vars.t rename to debian/modules/http-cache-purge/t/proxy2_vars.t diff --git a/debian/modules/nginx-dav-ext-module/README b/debian/modules/http-dav-ext/README similarity index 100% rename from debian/modules/nginx-dav-ext-module/README rename to debian/modules/http-dav-ext/README diff --git a/debian/modules/nginx-dav-ext-module/config b/debian/modules/http-dav-ext/config similarity index 100% rename from debian/modules/nginx-dav-ext-module/config rename to debian/modules/http-dav-ext/config diff --git a/debian/modules/nginx-dav-ext-module/ngx_http_dav_ext_module.c b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c similarity index 100% rename from debian/modules/nginx-dav-ext-module/ngx_http_dav_ext_module.c rename to debian/modules/http-dav-ext/ngx_http_dav_ext_module.c diff --git a/debian/modules/nginx-echo/LICENSE b/debian/modules/http-echo/LICENSE similarity index 100% rename from debian/modules/nginx-echo/LICENSE rename to debian/modules/http-echo/LICENSE diff --git a/debian/modules/nginx-echo/README.markdown b/debian/modules/http-echo/README.markdown similarity index 100% rename from debian/modules/nginx-echo/README.markdown rename to debian/modules/http-echo/README.markdown diff --git a/debian/modules/nginx-echo/config b/debian/modules/http-echo/config similarity index 100% rename from debian/modules/nginx-echo/config rename to debian/modules/http-echo/config diff --git a/debian/modules/nginx-echo/src/ddebug.h b/debian/modules/http-echo/src/ddebug.h similarity index 100% rename from debian/modules/nginx-echo/src/ddebug.h rename to debian/modules/http-echo/src/ddebug.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_echo.c b/debian/modules/http-echo/src/ngx_http_echo_echo.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_echo.c rename to debian/modules/http-echo/src/ngx_http_echo_echo.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_echo.h b/debian/modules/http-echo/src/ngx_http_echo_echo.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_echo.h rename to debian/modules/http-echo/src/ngx_http_echo_echo.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_filter.c b/debian/modules/http-echo/src/ngx_http_echo_filter.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_filter.c rename to debian/modules/http-echo/src/ngx_http_echo_filter.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_filter.h b/debian/modules/http-echo/src/ngx_http_echo_filter.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_filter.h rename to debian/modules/http-echo/src/ngx_http_echo_filter.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_foreach.c b/debian/modules/http-echo/src/ngx_http_echo_foreach.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_foreach.c rename to debian/modules/http-echo/src/ngx_http_echo_foreach.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_foreach.h b/debian/modules/http-echo/src/ngx_http_echo_foreach.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_foreach.h rename to debian/modules/http-echo/src/ngx_http_echo_foreach.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_handler.c b/debian/modules/http-echo/src/ngx_http_echo_handler.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_handler.c rename to debian/modules/http-echo/src/ngx_http_echo_handler.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_handler.h b/debian/modules/http-echo/src/ngx_http_echo_handler.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_handler.h rename to debian/modules/http-echo/src/ngx_http_echo_handler.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_location.c b/debian/modules/http-echo/src/ngx_http_echo_location.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_location.c rename to debian/modules/http-echo/src/ngx_http_echo_location.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_location.h b/debian/modules/http-echo/src/ngx_http_echo_location.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_location.h rename to debian/modules/http-echo/src/ngx_http_echo_location.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_module.c b/debian/modules/http-echo/src/ngx_http_echo_module.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_module.c rename to debian/modules/http-echo/src/ngx_http_echo_module.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_module.h b/debian/modules/http-echo/src/ngx_http_echo_module.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_module.h rename to debian/modules/http-echo/src/ngx_http_echo_module.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.c b/debian/modules/http-echo/src/ngx_http_echo_request_info.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_request_info.c rename to debian/modules/http-echo/src/ngx_http_echo_request_info.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_request_info.h b/debian/modules/http-echo/src/ngx_http_echo_request_info.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_request_info.h rename to debian/modules/http-echo/src/ngx_http_echo_request_info.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_sleep.c b/debian/modules/http-echo/src/ngx_http_echo_sleep.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_sleep.c rename to debian/modules/http-echo/src/ngx_http_echo_sleep.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_sleep.h b/debian/modules/http-echo/src/ngx_http_echo_sleep.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_sleep.h rename to debian/modules/http-echo/src/ngx_http_echo_sleep.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_subrequest.c b/debian/modules/http-echo/src/ngx_http_echo_subrequest.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_subrequest.c rename to debian/modules/http-echo/src/ngx_http_echo_subrequest.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_subrequest.h b/debian/modules/http-echo/src/ngx_http_echo_subrequest.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_subrequest.h rename to debian/modules/http-echo/src/ngx_http_echo_subrequest.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_timer.c b/debian/modules/http-echo/src/ngx_http_echo_timer.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_timer.c rename to debian/modules/http-echo/src/ngx_http_echo_timer.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_timer.h b/debian/modules/http-echo/src/ngx_http_echo_timer.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_timer.h rename to debian/modules/http-echo/src/ngx_http_echo_timer.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_util.c b/debian/modules/http-echo/src/ngx_http_echo_util.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_util.c rename to debian/modules/http-echo/src/ngx_http_echo_util.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_util.h b/debian/modules/http-echo/src/ngx_http_echo_util.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_util.h rename to debian/modules/http-echo/src/ngx_http_echo_util.h diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_var.c b/debian/modules/http-echo/src/ngx_http_echo_var.c similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_var.c rename to debian/modules/http-echo/src/ngx_http_echo_var.c diff --git a/debian/modules/nginx-echo/src/ngx_http_echo_var.h b/debian/modules/http-echo/src/ngx_http_echo_var.h similarity index 100% rename from debian/modules/nginx-echo/src/ngx_http_echo_var.h rename to debian/modules/http-echo/src/ngx_http_echo_var.h diff --git a/debian/modules/nginx-echo/t/abort-parent.t b/debian/modules/http-echo/t/abort-parent.t similarity index 100% rename from debian/modules/nginx-echo/t/abort-parent.t rename to debian/modules/http-echo/t/abort-parent.t diff --git a/debian/modules/nginx-echo/t/blocking-sleep.t b/debian/modules/http-echo/t/blocking-sleep.t similarity index 100% rename from debian/modules/nginx-echo/t/blocking-sleep.t rename to debian/modules/http-echo/t/blocking-sleep.t diff --git a/debian/modules/nginx-echo/t/echo-after-body.t b/debian/modules/http-echo/t/echo-after-body.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-after-body.t rename to debian/modules/http-echo/t/echo-after-body.t diff --git a/debian/modules/nginx-echo/t/echo-before-body.t b/debian/modules/http-echo/t/echo-before-body.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-before-body.t rename to debian/modules/http-echo/t/echo-before-body.t diff --git a/debian/modules/nginx-echo/t/echo-duplicate.t b/debian/modules/http-echo/t/echo-duplicate.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-duplicate.t rename to debian/modules/http-echo/t/echo-duplicate.t diff --git a/debian/modules/nginx-echo/t/echo-timer.t b/debian/modules/http-echo/t/echo-timer.t similarity index 100% rename from debian/modules/nginx-echo/t/echo-timer.t rename to debian/modules/http-echo/t/echo-timer.t diff --git a/debian/modules/nginx-echo/t/echo.t b/debian/modules/http-echo/t/echo.t similarity index 100% rename from debian/modules/nginx-echo/t/echo.t rename to debian/modules/http-echo/t/echo.t diff --git a/debian/modules/nginx-echo/t/exec.t b/debian/modules/http-echo/t/exec.t similarity index 100% rename from debian/modules/nginx-echo/t/exec.t rename to debian/modules/http-echo/t/exec.t diff --git a/debian/modules/nginx-echo/t/filter-used.t b/debian/modules/http-echo/t/filter-used.t similarity index 100% rename from debian/modules/nginx-echo/t/filter-used.t rename to debian/modules/http-echo/t/filter-used.t diff --git a/debian/modules/nginx-echo/t/foreach-split.t b/debian/modules/http-echo/t/foreach-split.t similarity index 100% rename from debian/modules/nginx-echo/t/foreach-split.t rename to debian/modules/http-echo/t/foreach-split.t diff --git a/debian/modules/nginx-echo/t/gzip.t b/debian/modules/http-echo/t/gzip.t similarity index 100% rename from debian/modules/nginx-echo/t/gzip.t rename to debian/modules/http-echo/t/gzip.t diff --git a/debian/modules/nginx-echo/t/if.t b/debian/modules/http-echo/t/if.t similarity index 100% rename from debian/modules/nginx-echo/t/if.t rename to debian/modules/http-echo/t/if.t diff --git a/debian/modules/nginx-echo/t/incr.t b/debian/modules/http-echo/t/incr.t similarity index 100% rename from debian/modules/nginx-echo/t/incr.t rename to debian/modules/http-echo/t/incr.t diff --git a/debian/modules/nginx-echo/t/location-async.t b/debian/modules/http-echo/t/location-async.t similarity index 100% rename from debian/modules/nginx-echo/t/location-async.t rename to debian/modules/http-echo/t/location-async.t diff --git a/debian/modules/nginx-echo/t/location.t b/debian/modules/http-echo/t/location.t similarity index 100% rename from debian/modules/nginx-echo/t/location.t rename to debian/modules/http-echo/t/location.t diff --git a/debian/modules/nginx-echo/t/mixed.t b/debian/modules/http-echo/t/mixed.t similarity index 100% rename from debian/modules/nginx-echo/t/mixed.t rename to debian/modules/http-echo/t/mixed.t diff --git a/debian/modules/nginx-echo/t/request-body.t b/debian/modules/http-echo/t/request-body.t similarity index 100% rename from debian/modules/nginx-echo/t/request-body.t rename to debian/modules/http-echo/t/request-body.t diff --git a/debian/modules/nginx-echo/t/request-info.t b/debian/modules/http-echo/t/request-info.t similarity index 100% rename from debian/modules/nginx-echo/t/request-info.t rename to debian/modules/http-echo/t/request-info.t diff --git a/debian/modules/nginx-echo/t/sleep.t b/debian/modules/http-echo/t/sleep.t similarity index 100% rename from debian/modules/nginx-echo/t/sleep.t rename to debian/modules/http-echo/t/sleep.t diff --git a/debian/modules/nginx-echo/t/status.t b/debian/modules/http-echo/t/status.t similarity index 100% rename from debian/modules/nginx-echo/t/status.t rename to debian/modules/http-echo/t/status.t diff --git a/debian/modules/nginx-echo/t/subrequest-async.t b/debian/modules/http-echo/t/subrequest-async.t similarity index 100% rename from debian/modules/nginx-echo/t/subrequest-async.t rename to debian/modules/http-echo/t/subrequest-async.t diff --git a/debian/modules/nginx-echo/t/subrequest.t b/debian/modules/http-echo/t/subrequest.t similarity index 100% rename from debian/modules/nginx-echo/t/subrequest.t rename to debian/modules/http-echo/t/subrequest.t diff --git a/debian/modules/nginx-echo/t/unused.t b/debian/modules/http-echo/t/unused.t similarity index 100% rename from debian/modules/nginx-echo/t/unused.t rename to debian/modules/http-echo/t/unused.t diff --git a/debian/modules/nginx-echo/util/build.sh b/debian/modules/http-echo/util/build.sh similarity index 100% rename from debian/modules/nginx-echo/util/build.sh rename to debian/modules/http-echo/util/build.sh diff --git a/debian/modules/nginx-echo/util/releng b/debian/modules/http-echo/util/releng similarity index 100% rename from debian/modules/nginx-echo/util/releng rename to debian/modules/http-echo/util/releng diff --git a/debian/modules/nginx-echo/util/wiki2pod.pl b/debian/modules/http-echo/util/wiki2pod.pl similarity index 100% rename from debian/modules/nginx-echo/util/wiki2pod.pl rename to debian/modules/http-echo/util/wiki2pod.pl diff --git a/debian/modules/nginx-echo/valgrind.suppress b/debian/modules/http-echo/valgrind.suppress similarity index 100% rename from debian/modules/nginx-echo/valgrind.suppress rename to debian/modules/http-echo/valgrind.suppress diff --git a/debian/modules/ngx-fancyindex/CHANGELOG.md b/debian/modules/http-fancyindex/CHANGELOG.md similarity index 100% rename from debian/modules/ngx-fancyindex/CHANGELOG.md rename to debian/modules/http-fancyindex/CHANGELOG.md diff --git a/debian/modules/ngx-fancyindex/HACKING.md b/debian/modules/http-fancyindex/HACKING.md similarity index 100% rename from debian/modules/ngx-fancyindex/HACKING.md rename to debian/modules/http-fancyindex/HACKING.md diff --git a/debian/modules/ngx-fancyindex/LICENSE b/debian/modules/http-fancyindex/LICENSE similarity index 100% rename from debian/modules/ngx-fancyindex/LICENSE rename to debian/modules/http-fancyindex/LICENSE diff --git a/debian/modules/ngx-fancyindex/README.rst b/debian/modules/http-fancyindex/README.rst similarity index 100% rename from debian/modules/ngx-fancyindex/README.rst rename to debian/modules/http-fancyindex/README.rst diff --git a/debian/modules/ngx-fancyindex/config b/debian/modules/http-fancyindex/config similarity index 100% rename from debian/modules/ngx-fancyindex/config rename to debian/modules/http-fancyindex/config diff --git a/debian/modules/ngx-fancyindex/nginx-0.6-support.patch b/debian/modules/http-fancyindex/nginx-0.6-support.patch similarity index 100% rename from debian/modules/ngx-fancyindex/nginx-0.6-support.patch rename to debian/modules/http-fancyindex/nginx-0.6-support.patch diff --git a/debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c similarity index 100% rename from debian/modules/ngx-fancyindex/ngx_http_fancyindex_module.c rename to debian/modules/http-fancyindex/ngx_http_fancyindex_module.c diff --git a/debian/modules/ngx-fancyindex/t/00-build-artifacts.test b/debian/modules/http-fancyindex/t/00-build-artifacts.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/00-build-artifacts.test rename to debian/modules/http-fancyindex/t/00-build-artifacts.test diff --git a/debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test b/debian/modules/http-fancyindex/t/01-smoke-hasindex.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/01-smoke-hasindex.test rename to debian/modules/http-fancyindex/t/01-smoke-hasindex.test diff --git a/debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test b/debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/02-smoke-indexisfancy.test rename to debian/modules/http-fancyindex/t/02-smoke-indexisfancy.test diff --git a/debian/modules/ngx-fancyindex/t/build-and-run b/debian/modules/http-fancyindex/t/build-and-run similarity index 100% rename from debian/modules/ngx-fancyindex/t/build-and-run rename to debian/modules/http-fancyindex/t/build-and-run diff --git a/debian/modules/ngx-fancyindex/t/has-index.test b/debian/modules/http-fancyindex/t/has-index.test similarity index 100% rename from debian/modules/ngx-fancyindex/t/has-index.test rename to debian/modules/http-fancyindex/t/has-index.test diff --git a/debian/modules/ngx-fancyindex/t/has-index/index.html b/debian/modules/http-fancyindex/t/has-index/index.html similarity index 100% rename from debian/modules/ngx-fancyindex/t/has-index/index.html rename to debian/modules/http-fancyindex/t/has-index/index.html diff --git a/debian/modules/ngx-fancyindex/t/nginx.conf b/debian/modules/http-fancyindex/t/nginx.conf similarity index 100% rename from debian/modules/ngx-fancyindex/t/nginx.conf rename to debian/modules/http-fancyindex/t/nginx.conf diff --git a/debian/modules/ngx-fancyindex/t/preamble b/debian/modules/http-fancyindex/t/preamble similarity index 100% rename from debian/modules/ngx-fancyindex/t/preamble rename to debian/modules/http-fancyindex/t/preamble diff --git a/debian/modules/ngx-fancyindex/t/run b/debian/modules/http-fancyindex/t/run similarity index 100% rename from debian/modules/ngx-fancyindex/t/run rename to debian/modules/http-fancyindex/t/run diff --git a/debian/modules/ngx-fancyindex/template.awk b/debian/modules/http-fancyindex/template.awk similarity index 100% rename from debian/modules/ngx-fancyindex/template.awk rename to debian/modules/http-fancyindex/template.awk diff --git a/debian/modules/ngx-fancyindex/template.h b/debian/modules/http-fancyindex/template.h similarity index 100% rename from debian/modules/ngx-fancyindex/template.h rename to debian/modules/http-fancyindex/template.h diff --git a/debian/modules/ngx-fancyindex/template.html b/debian/modules/http-fancyindex/template.html similarity index 100% rename from debian/modules/ngx-fancyindex/template.html rename to debian/modules/http-fancyindex/template.html diff --git a/debian/modules/headers-more-nginx-module/README.markdown b/debian/modules/http-headers-more-filter/README.markdown similarity index 100% rename from debian/modules/headers-more-nginx-module/README.markdown rename to debian/modules/http-headers-more-filter/README.markdown diff --git a/debian/modules/headers-more-nginx-module/config b/debian/modules/http-headers-more-filter/config similarity index 100% rename from debian/modules/headers-more-nginx-module/config rename to debian/modules/http-headers-more-filter/config diff --git a/debian/modules/headers-more-nginx-module/src/ddebug.h b/debian/modules/http-headers-more-filter/src/ddebug.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ddebug.h rename to debian/modules/http-headers-more-filter/src/ddebug.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_filter_module.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_filter_module.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_in.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_headers_out.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_out.h diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.c rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.c diff --git a/debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.h b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h similarity index 100% rename from debian/modules/headers-more-nginx-module/src/ngx_http_headers_more_util.h rename to debian/modules/http-headers-more-filter/src/ngx_http_headers_more_util.h diff --git a/debian/modules/headers-more-nginx-module/t/bug.t b/debian/modules/http-headers-more-filter/t/bug.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/bug.t rename to debian/modules/http-headers-more-filter/t/bug.t diff --git a/debian/modules/headers-more-nginx-module/t/builtin.t b/debian/modules/http-headers-more-filter/t/builtin.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/builtin.t rename to debian/modules/http-headers-more-filter/t/builtin.t diff --git a/debian/modules/headers-more-nginx-module/t/eval.t b/debian/modules/http-headers-more-filter/t/eval.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/eval.t rename to debian/modules/http-headers-more-filter/t/eval.t diff --git a/debian/modules/headers-more-nginx-module/t/input-conn.t b/debian/modules/http-headers-more-filter/t/input-conn.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input-conn.t rename to debian/modules/http-headers-more-filter/t/input-conn.t diff --git a/debian/modules/headers-more-nginx-module/t/input-cookie.t b/debian/modules/http-headers-more-filter/t/input-cookie.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input-cookie.t rename to debian/modules/http-headers-more-filter/t/input-cookie.t diff --git a/debian/modules/headers-more-nginx-module/t/input-ua.t b/debian/modules/http-headers-more-filter/t/input-ua.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input-ua.t rename to debian/modules/http-headers-more-filter/t/input-ua.t diff --git a/debian/modules/headers-more-nginx-module/t/input.t b/debian/modules/http-headers-more-filter/t/input.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/input.t rename to debian/modules/http-headers-more-filter/t/input.t diff --git a/debian/modules/headers-more-nginx-module/t/phase.t b/debian/modules/http-headers-more-filter/t/phase.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/phase.t rename to debian/modules/http-headers-more-filter/t/phase.t diff --git a/debian/modules/headers-more-nginx-module/t/sanity.t b/debian/modules/http-headers-more-filter/t/sanity.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/sanity.t rename to debian/modules/http-headers-more-filter/t/sanity.t diff --git a/debian/modules/headers-more-nginx-module/t/subrequest.t b/debian/modules/http-headers-more-filter/t/subrequest.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/subrequest.t rename to debian/modules/http-headers-more-filter/t/subrequest.t diff --git a/debian/modules/headers-more-nginx-module/t/unused.t b/debian/modules/http-headers-more-filter/t/unused.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/unused.t rename to debian/modules/http-headers-more-filter/t/unused.t diff --git a/debian/modules/headers-more-nginx-module/t/vars.t b/debian/modules/http-headers-more-filter/t/vars.t similarity index 100% rename from debian/modules/headers-more-nginx-module/t/vars.t rename to debian/modules/http-headers-more-filter/t/vars.t diff --git a/debian/modules/headers-more-nginx-module/util/build.sh b/debian/modules/http-headers-more-filter/util/build.sh similarity index 100% rename from debian/modules/headers-more-nginx-module/util/build.sh rename to debian/modules/http-headers-more-filter/util/build.sh diff --git a/debian/modules/headers-more-nginx-module/valgrind.suppress b/debian/modules/http-headers-more-filter/valgrind.suppress similarity index 100% rename from debian/modules/headers-more-nginx-module/valgrind.suppress rename to debian/modules/http-headers-more-filter/valgrind.suppress diff --git a/debian/modules/nginx-lua/README.markdown b/debian/modules/http-lua/README.markdown similarity index 100% rename from debian/modules/nginx-lua/README.markdown rename to debian/modules/http-lua/README.markdown diff --git a/debian/modules/nginx-lua/config b/debian/modules/http-lua/config similarity index 100% rename from debian/modules/nginx-lua/config rename to debian/modules/http-lua/config diff --git a/debian/modules/nginx-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki similarity index 100% rename from debian/modules/nginx-lua/doc/HttpLuaModule.wiki rename to debian/modules/http-lua/doc/HttpLuaModule.wiki diff --git a/debian/modules/nginx-lua/dtrace/ngx_lua_provider.d b/debian/modules/http-lua/dtrace/ngx_lua_provider.d similarity index 100% rename from debian/modules/nginx-lua/dtrace/ngx_lua_provider.d rename to debian/modules/http-lua/dtrace/ngx_lua_provider.d diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/Makefile b/debian/modules/http-lua/misc/recv-until-pm/Makefile similarity index 100% rename from debian/modules/nginx-lua/misc/recv-until-pm/Makefile rename to debian/modules/http-lua/misc/recv-until-pm/Makefile diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/lib/RecvUntil.pm b/debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm similarity index 100% rename from debian/modules/nginx-lua/misc/recv-until-pm/lib/RecvUntil.pm rename to debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm diff --git a/debian/modules/nginx-lua/misc/recv-until-pm/t/sanity.t b/debian/modules/http-lua/misc/recv-until-pm/t/sanity.t similarity index 100% rename from debian/modules/nginx-lua/misc/recv-until-pm/t/sanity.t rename to debian/modules/http-lua/misc/recv-until-pm/t/sanity.t diff --git a/debian/modules/nginx-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h similarity index 100% rename from debian/modules/nginx-lua/src/api/ngx_http_lua_api.h rename to debian/modules/http-lua/src/api/ngx_http_lua_api.h diff --git a/debian/modules/nginx-lua/src/ddebug.h b/debian/modules/http-lua/src/ddebug.h similarity index 100% rename from debian/modules/nginx-lua/src/ddebug.h rename to debian/modules/http-lua/src/ddebug.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_accessby.c rename to debian/modules/http-lua/src/ngx_http_lua_accessby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_accessby.h b/debian/modules/http-lua/src/ngx_http_lua_accessby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_accessby.h rename to debian/modules/http-lua/src/ngx_http_lua_accessby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_api.c b/debian/modules/http-lua/src/ngx_http_lua_api.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_api.c rename to debian/modules/http-lua/src/ngx_http_lua_api.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.c b/debian/modules/http-lua/src/ngx_http_lua_args.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_args.c rename to debian/modules/http-lua/src/ngx_http_lua_args.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_args.h b/debian/modules/http-lua/src/ngx_http_lua_args.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_args.h rename to debian/modules/http-lua/src/ngx_http_lua_args.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.c b/debian/modules/http-lua/src/ngx_http_lua_balancer.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_balancer.c rename to debian/modules/http-lua/src/ngx_http_lua_balancer.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_balancer.h b/debian/modules/http-lua/src/ngx_http_lua_balancer.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_balancer.h rename to debian/modules/http-lua/src/ngx_http_lua_balancer.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.c rename to debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_bodyfilterby.h rename to debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.c b/debian/modules/http-lua/src/ngx_http_lua_cache.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_cache.c rename to debian/modules/http-lua/src/ngx_http_lua_cache.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_cache.h b/debian/modules/http-lua/src/ngx_http_lua_cache.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_cache.h rename to debian/modules/http-lua/src/ngx_http_lua_cache.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c b/debian/modules/http-lua/src/ngx_http_lua_capturefilter.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.c rename to debian/modules/http-lua/src/ngx_http_lua_capturefilter.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.h b/debian/modules/http-lua/src/ngx_http_lua_capturefilter.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_capturefilter.h rename to debian/modules/http-lua/src/ngx_http_lua_capturefilter.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c b/debian/modules/http-lua/src/ngx_http_lua_clfactory.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_clfactory.c rename to debian/modules/http-lua/src/ngx_http_lua_clfactory.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_clfactory.h b/debian/modules/http-lua/src/ngx_http_lua_clfactory.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_clfactory.h rename to debian/modules/http-lua/src/ngx_http_lua_clfactory.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_common.h b/debian/modules/http-lua/src/ngx_http_lua_common.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_common.h rename to debian/modules/http-lua/src/ngx_http_lua_common.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_config.c b/debian/modules/http-lua/src/ngx_http_lua_config.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_config.c rename to debian/modules/http-lua/src/ngx_http_lua_config.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_config.h b/debian/modules/http-lua/src/ngx_http_lua_config.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_config.h rename to debian/modules/http-lua/src/ngx_http_lua_config.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_consts.c b/debian/modules/http-lua/src/ngx_http_lua_consts.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_consts.c rename to debian/modules/http-lua/src/ngx_http_lua_consts.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_consts.h b/debian/modules/http-lua/src/ngx_http_lua_consts.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_consts.h rename to debian/modules/http-lua/src/ngx_http_lua_consts.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.c b/debian/modules/http-lua/src/ngx_http_lua_contentby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_contentby.c rename to debian/modules/http-lua/src/ngx_http_lua_contentby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_contentby.h b/debian/modules/http-lua/src/ngx_http_lua_contentby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_contentby.h rename to debian/modules/http-lua/src/ngx_http_lua_contentby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.c b/debian/modules/http-lua/src/ngx_http_lua_control.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_control.c rename to debian/modules/http-lua/src/ngx_http_lua_control.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_control.h b/debian/modules/http-lua/src/ngx_http_lua_control.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_control.h rename to debian/modules/http-lua/src/ngx_http_lua_control.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c b/debian/modules/http-lua/src/ngx_http_lua_coroutine.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_coroutine.c rename to debian/modules/http-lua/src/ngx_http_lua_coroutine.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_coroutine.h b/debian/modules/http-lua/src/ngx_http_lua_coroutine.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_coroutine.h rename to debian/modules/http-lua/src/ngx_http_lua_coroutine.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ctx.c b/debian/modules/http-lua/src/ngx_http_lua_ctx.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ctx.c rename to debian/modules/http-lua/src/ngx_http_lua_ctx.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ctx.h b/debian/modules/http-lua/src/ngx_http_lua_ctx.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ctx.h rename to debian/modules/http-lua/src/ngx_http_lua_ctx.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_directive.c rename to debian/modules/http-lua/src/ngx_http_lua_directive.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_directive.h b/debian/modules/http-lua/src/ngx_http_lua_directive.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_directive.h rename to debian/modules/http-lua/src/ngx_http_lua_directive.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_exception.c b/debian/modules/http-lua/src/ngx_http_lua_exception.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_exception.c rename to debian/modules/http-lua/src/ngx_http_lua_exception.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_exception.h b/debian/modules/http-lua/src/ngx_http_lua_exception.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_exception.h rename to debian/modules/http-lua/src/ngx_http_lua_exception.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.c rename to debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.h b/debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headerfilterby.h rename to debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.c b/debian/modules/http-lua/src/ngx_http_lua_headers.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers.c rename to debian/modules/http-lua/src/ngx_http_lua_headers.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers.h b/debian/modules/http-lua/src/ngx_http_lua_headers.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers.h rename to debian/modules/http-lua/src/ngx_http_lua_headers.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c b/debian/modules/http-lua/src/ngx_http_lua_headers_in.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_in.c rename to debian/modules/http-lua/src/ngx_http_lua_headers_in.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_in.h b/debian/modules/http-lua/src/ngx_http_lua_headers_in.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_in.h rename to debian/modules/http-lua/src/ngx_http_lua_headers_in.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c b/debian/modules/http-lua/src/ngx_http_lua_headers_out.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_out.c rename to debian/modules/http-lua/src/ngx_http_lua_headers_out.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_headers_out.h b/debian/modules/http-lua/src/ngx_http_lua_headers_out.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_headers_out.h rename to debian/modules/http-lua/src/ngx_http_lua_headers_out.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initby.c b/debian/modules/http-lua/src/ngx_http_lua_initby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initby.c rename to debian/modules/http-lua/src/ngx_http_lua_initby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initby.h b/debian/modules/http-lua/src/ngx_http_lua_initby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initby.h rename to debian/modules/http-lua/src/ngx_http_lua_initby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.c rename to debian/modules/http-lua/src/ngx_http_lua_initworkerby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.h b/debian/modules/http-lua/src/ngx_http_lua_initworkerby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_initworkerby.h rename to debian/modules/http-lua/src/ngx_http_lua_initworkerby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_lex.c b/debian/modules/http-lua/src/ngx_http_lua_lex.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_lex.c rename to debian/modules/http-lua/src/ngx_http_lua_lex.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_lex.h b/debian/modules/http-lua/src/ngx_http_lua_lex.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_lex.h rename to debian/modules/http-lua/src/ngx_http_lua_lex.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.c b/debian/modules/http-lua/src/ngx_http_lua_log.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log.c rename to debian/modules/http-lua/src/ngx_http_lua_log.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log.h b/debian/modules/http-lua/src/ngx_http_lua_log.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log.h rename to debian/modules/http-lua/src/ngx_http_lua_log.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c b/debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.c rename to debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h b/debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_log_ringbuf.h rename to debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.c b/debian/modules/http-lua/src/ngx_http_lua_logby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_logby.c rename to debian/modules/http-lua/src/ngx_http_lua_logby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_logby.h b/debian/modules/http-lua/src/ngx_http_lua_logby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_logby.h rename to debian/modules/http-lua/src/ngx_http_lua_logby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.c b/debian/modules/http-lua/src/ngx_http_lua_misc.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_misc.c rename to debian/modules/http-lua/src/ngx_http_lua_misc.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_misc.h b/debian/modules/http-lua/src/ngx_http_lua_misc.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_misc.h rename to debian/modules/http-lua/src/ngx_http_lua_misc.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_module.c b/debian/modules/http-lua/src/ngx_http_lua_module.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_module.c rename to debian/modules/http-lua/src/ngx_http_lua_module.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ndk.c b/debian/modules/http-lua/src/ngx_http_lua_ndk.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ndk.c rename to debian/modules/http-lua/src/ngx_http_lua_ndk.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ndk.h b/debian/modules/http-lua/src/ngx_http_lua_ndk.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ndk.h rename to debian/modules/http-lua/src/ngx_http_lua_ndk.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.c b/debian/modules/http-lua/src/ngx_http_lua_output.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_output.c rename to debian/modules/http-lua/src/ngx_http_lua_output.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_output.h b/debian/modules/http-lua/src/ngx_http_lua_output.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_output.h rename to debian/modules/http-lua/src/ngx_http_lua_output.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.c b/debian/modules/http-lua/src/ngx_http_lua_pcrefix.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.c rename to debian/modules/http-lua/src/ngx_http_lua_pcrefix.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.h b/debian/modules/http-lua/src/ngx_http_lua_pcrefix.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_pcrefix.h rename to debian/modules/http-lua/src/ngx_http_lua_pcrefix.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.c b/debian/modules/http-lua/src/ngx_http_lua_phase.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_phase.c rename to debian/modules/http-lua/src/ngx_http_lua_phase.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_phase.h b/debian/modules/http-lua/src/ngx_http_lua_phase.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_phase.h rename to debian/modules/http-lua/src/ngx_http_lua_phase.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_probe.h b/debian/modules/http-lua/src/ngx_http_lua_probe.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_probe.h rename to debian/modules/http-lua/src/ngx_http_lua_probe.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.c b/debian/modules/http-lua/src/ngx_http_lua_regex.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_regex.c rename to debian/modules/http-lua/src/ngx_http_lua_regex.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_regex.h b/debian/modules/http-lua/src/ngx_http_lua_regex.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_regex.h rename to debian/modules/http-lua/src/ngx_http_lua_regex.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.c b/debian/modules/http-lua/src/ngx_http_lua_req_body.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_body.c rename to debian/modules/http-lua/src/ngx_http_lua_req_body.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_body.h b/debian/modules/http-lua/src/ngx_http_lua_req_body.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_body.h rename to debian/modules/http-lua/src/ngx_http_lua_req_body.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_method.c b/debian/modules/http-lua/src/ngx_http_lua_req_method.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_method.c rename to debian/modules/http-lua/src/ngx_http_lua_req_method.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_req_method.h b/debian/modules/http-lua/src/ngx_http_lua_req_method.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_req_method.h rename to debian/modules/http-lua/src/ngx_http_lua_req_method.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.c rename to debian/modules/http-lua/src/ngx_http_lua_rewriteby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.h b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_rewriteby.h rename to debian/modules/http-lua/src/ngx_http_lua_rewriteby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.c b/debian/modules/http-lua/src/ngx_http_lua_script.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_script.c rename to debian/modules/http-lua/src/ngx_http_lua_script.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_script.h b/debian/modules/http-lua/src/ngx_http_lua_script.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_script.h rename to debian/modules/http-lua/src/ngx_http_lua_script.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c b/debian/modules/http-lua/src/ngx_http_lua_semaphore.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_semaphore.c rename to debian/modules/http-lua/src/ngx_http_lua_semaphore.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h b/debian/modules/http-lua/src/ngx_http_lua_semaphore.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_semaphore.h rename to debian/modules/http-lua/src/ngx_http_lua_semaphore.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_setby.c b/debian/modules/http-lua/src/ngx_http_lua_setby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_setby.c rename to debian/modules/http-lua/src/ngx_http_lua_setby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_setby.h b/debian/modules/http-lua/src/ngx_http_lua_setby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_setby.h rename to debian/modules/http-lua/src/ngx_http_lua_setby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_shdict.c rename to debian/modules/http-lua/src/ngx_http_lua_shdict.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_shdict.h b/debian/modules/http-lua/src/ngx_http_lua_shdict.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_shdict.h rename to debian/modules/http-lua/src/ngx_http_lua_shdict.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.c b/debian/modules/http-lua/src/ngx_http_lua_sleep.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_sleep.c rename to debian/modules/http-lua/src/ngx_http_lua_sleep.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_sleep.h b/debian/modules/http-lua/src/ngx_http_lua_sleep.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_sleep.h rename to debian/modules/http-lua/src/ngx_http_lua_sleep.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.c rename to debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_tcp.h rename to debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.c rename to debian/modules/http-lua/src/ngx_http_lua_socket_udp.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_socket_udp.h rename to debian/modules/http-lua/src/ngx_http_lua_socket_udp.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.c b/debian/modules/http-lua/src/ngx_http_lua_ssl.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl.h b/debian/modules/http-lua/src/ngx_http_lua_ssl.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_certby.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_ocsp.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_fetchby.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.c rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_ssl_session_storeby.h rename to debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.c b/debian/modules/http-lua/src/ngx_http_lua_string.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_string.c rename to debian/modules/http-lua/src/ngx_http_lua_string.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_string.h b/debian/modules/http-lua/src/ngx_http_lua_string.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_string.h rename to debian/modules/http-lua/src/ngx_http_lua_string.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_subrequest.c rename to debian/modules/http-lua/src/ngx_http_lua_subrequest.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_subrequest.h b/debian/modules/http-lua/src/ngx_http_lua_subrequest.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_subrequest.h rename to debian/modules/http-lua/src/ngx_http_lua_subrequest.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_time.c b/debian/modules/http-lua/src/ngx_http_lua_time.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_time.c rename to debian/modules/http-lua/src/ngx_http_lua_time.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_time.h b/debian/modules/http-lua/src/ngx_http_lua_time.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_time.h rename to debian/modules/http-lua/src/ngx_http_lua_time.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.c b/debian/modules/http-lua/src/ngx_http_lua_timer.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_timer.c rename to debian/modules/http-lua/src/ngx_http_lua_timer.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_timer.h b/debian/modules/http-lua/src/ngx_http_lua_timer.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_timer.h rename to debian/modules/http-lua/src/ngx_http_lua_timer.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uri.c b/debian/modules/http-lua/src/ngx_http_lua_uri.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uri.c rename to debian/modules/http-lua/src/ngx_http_lua_uri.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uri.h b/debian/modules/http-lua/src/ngx_http_lua_uri.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uri.h rename to debian/modules/http-lua/src/ngx_http_lua_uri.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uthread.c b/debian/modules/http-lua/src/ngx_http_lua_uthread.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uthread.c rename to debian/modules/http-lua/src/ngx_http_lua_uthread.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_uthread.h b/debian/modules/http-lua/src/ngx_http_lua_uthread.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_uthread.h rename to debian/modules/http-lua/src/ngx_http_lua_uthread.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_util.c rename to debian/modules/http-lua/src/ngx_http_lua_util.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_util.h rename to debian/modules/http-lua/src/ngx_http_lua_util.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_variable.c b/debian/modules/http-lua/src/ngx_http_lua_variable.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_variable.c rename to debian/modules/http-lua/src/ngx_http_lua_variable.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_variable.h b/debian/modules/http-lua/src/ngx_http_lua_variable.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_variable.h rename to debian/modules/http-lua/src/ngx_http_lua_variable.h diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.c b/debian/modules/http-lua/src/ngx_http_lua_worker.c similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_worker.c rename to debian/modules/http-lua/src/ngx_http_lua_worker.c diff --git a/debian/modules/nginx-lua/src/ngx_http_lua_worker.h b/debian/modules/http-lua/src/ngx_http_lua_worker.h similarity index 100% rename from debian/modules/nginx-lua/src/ngx_http_lua_worker.h rename to debian/modules/http-lua/src/ngx_http_lua_worker.h diff --git a/debian/modules/nginx-lua/t/.gitignore b/debian/modules/http-lua/t/.gitignore similarity index 100% rename from debian/modules/nginx-lua/t/.gitignore rename to debian/modules/http-lua/t/.gitignore diff --git a/debian/modules/nginx-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t similarity index 100% rename from debian/modules/nginx-lua/t/000--init.t rename to debian/modules/http-lua/t/000--init.t diff --git a/debian/modules/nginx-lua/t/000-sanity.t b/debian/modules/http-lua/t/000-sanity.t similarity index 100% rename from debian/modules/nginx-lua/t/000-sanity.t rename to debian/modules/http-lua/t/000-sanity.t diff --git a/debian/modules/nginx-lua/t/001-set.t b/debian/modules/http-lua/t/001-set.t similarity index 100% rename from debian/modules/nginx-lua/t/001-set.t rename to debian/modules/http-lua/t/001-set.t diff --git a/debian/modules/nginx-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t similarity index 100% rename from debian/modules/nginx-lua/t/002-content.t rename to debian/modules/http-lua/t/002-content.t diff --git a/debian/modules/nginx-lua/t/003-errors.t b/debian/modules/http-lua/t/003-errors.t similarity index 100% rename from debian/modules/nginx-lua/t/003-errors.t rename to debian/modules/http-lua/t/003-errors.t diff --git a/debian/modules/nginx-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t similarity index 100% rename from debian/modules/nginx-lua/t/004-require.t rename to debian/modules/http-lua/t/004-require.t diff --git a/debian/modules/nginx-lua/t/005-exit.t b/debian/modules/http-lua/t/005-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/005-exit.t rename to debian/modules/http-lua/t/005-exit.t diff --git a/debian/modules/nginx-lua/t/006-escape.t b/debian/modules/http-lua/t/006-escape.t similarity index 100% rename from debian/modules/nginx-lua/t/006-escape.t rename to debian/modules/http-lua/t/006-escape.t diff --git a/debian/modules/nginx-lua/t/007-md5.t b/debian/modules/http-lua/t/007-md5.t similarity index 100% rename from debian/modules/nginx-lua/t/007-md5.t rename to debian/modules/http-lua/t/007-md5.t diff --git a/debian/modules/nginx-lua/t/008-today.t b/debian/modules/http-lua/t/008-today.t similarity index 100% rename from debian/modules/nginx-lua/t/008-today.t rename to debian/modules/http-lua/t/008-today.t diff --git a/debian/modules/nginx-lua/t/009-log.t b/debian/modules/http-lua/t/009-log.t similarity index 100% rename from debian/modules/nginx-lua/t/009-log.t rename to debian/modules/http-lua/t/009-log.t diff --git a/debian/modules/nginx-lua/t/010-request_body.t b/debian/modules/http-lua/t/010-request_body.t similarity index 100% rename from debian/modules/nginx-lua/t/010-request_body.t rename to debian/modules/http-lua/t/010-request_body.t diff --git a/debian/modules/nginx-lua/t/011-md5_bin.t b/debian/modules/http-lua/t/011-md5_bin.t similarity index 100% rename from debian/modules/nginx-lua/t/011-md5_bin.t rename to debian/modules/http-lua/t/011-md5_bin.t diff --git a/debian/modules/nginx-lua/t/012-now.t b/debian/modules/http-lua/t/012-now.t similarity index 100% rename from debian/modules/nginx-lua/t/012-now.t rename to debian/modules/http-lua/t/012-now.t diff --git a/debian/modules/nginx-lua/t/013-base64.t b/debian/modules/http-lua/t/013-base64.t similarity index 100% rename from debian/modules/nginx-lua/t/013-base64.t rename to debian/modules/http-lua/t/013-base64.t diff --git a/debian/modules/nginx-lua/t/014-bugs.t b/debian/modules/http-lua/t/014-bugs.t similarity index 100% rename from debian/modules/nginx-lua/t/014-bugs.t rename to debian/modules/http-lua/t/014-bugs.t diff --git a/debian/modules/nginx-lua/t/015-status.t b/debian/modules/http-lua/t/015-status.t similarity index 100% rename from debian/modules/nginx-lua/t/015-status.t rename to debian/modules/http-lua/t/015-status.t diff --git a/debian/modules/nginx-lua/t/016-resp-header.t b/debian/modules/http-lua/t/016-resp-header.t similarity index 100% rename from debian/modules/nginx-lua/t/016-resp-header.t rename to debian/modules/http-lua/t/016-resp-header.t diff --git a/debian/modules/nginx-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/017-exec.t rename to debian/modules/http-lua/t/017-exec.t diff --git a/debian/modules/nginx-lua/t/018-ndk.t b/debian/modules/http-lua/t/018-ndk.t similarity index 100% rename from debian/modules/nginx-lua/t/018-ndk.t rename to debian/modules/http-lua/t/018-ndk.t diff --git a/debian/modules/nginx-lua/t/019-const.t b/debian/modules/http-lua/t/019-const.t similarity index 100% rename from debian/modules/nginx-lua/t/019-const.t rename to debian/modules/http-lua/t/019-const.t diff --git a/debian/modules/nginx-lua/t/020-subrequest.t b/debian/modules/http-lua/t/020-subrequest.t similarity index 100% rename from debian/modules/nginx-lua/t/020-subrequest.t rename to debian/modules/http-lua/t/020-subrequest.t diff --git a/debian/modules/nginx-lua/t/021-cookie-time.t b/debian/modules/http-lua/t/021-cookie-time.t similarity index 100% rename from debian/modules/nginx-lua/t/021-cookie-time.t rename to debian/modules/http-lua/t/021-cookie-time.t diff --git a/debian/modules/nginx-lua/t/022-redirect.t b/debian/modules/http-lua/t/022-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/022-redirect.t rename to debian/modules/http-lua/t/022-redirect.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/client-abort.t b/debian/modules/http-lua/t/023-rewrite/client-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/client-abort.t rename to debian/modules/http-lua/t/023-rewrite/client-abort.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/exec.t rename to debian/modules/http-lua/t/023-rewrite/exec.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/exit.t b/debian/modules/http-lua/t/023-rewrite/exit.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/exit.t rename to debian/modules/http-lua/t/023-rewrite/exit.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/mixed.t b/debian/modules/http-lua/t/023-rewrite/mixed.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/mixed.t rename to debian/modules/http-lua/t/023-rewrite/mixed.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/multi-capture.t b/debian/modules/http-lua/t/023-rewrite/multi-capture.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/multi-capture.t rename to debian/modules/http-lua/t/023-rewrite/multi-capture.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/on-abort.t b/debian/modules/http-lua/t/023-rewrite/on-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/on-abort.t rename to debian/modules/http-lua/t/023-rewrite/on-abort.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/redirect.t b/debian/modules/http-lua/t/023-rewrite/redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/redirect.t rename to debian/modules/http-lua/t/023-rewrite/redirect.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-body.t b/debian/modules/http-lua/t/023-rewrite/req-body.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/req-body.t rename to debian/modules/http-lua/t/023-rewrite/req-body.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/req-socket.t b/debian/modules/http-lua/t/023-rewrite/req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/req-socket.t rename to debian/modules/http-lua/t/023-rewrite/req-socket.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/request_body.t b/debian/modules/http-lua/t/023-rewrite/request_body.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/request_body.t rename to debian/modules/http-lua/t/023-rewrite/request_body.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/sanity.t b/debian/modules/http-lua/t/023-rewrite/sanity.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/sanity.t rename to debian/modules/http-lua/t/023-rewrite/sanity.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/sleep.t b/debian/modules/http-lua/t/023-rewrite/sleep.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/sleep.t rename to debian/modules/http-lua/t/023-rewrite/sleep.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t b/debian/modules/http-lua/t/023-rewrite/socket-keepalive.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/socket-keepalive.t rename to debian/modules/http-lua/t/023-rewrite/socket-keepalive.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/subrequest.t b/debian/modules/http-lua/t/023-rewrite/subrequest.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/subrequest.t rename to debian/modules/http-lua/t/023-rewrite/subrequest.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/tcp-socket-timeout.t rename to debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/tcp-socket.t rename to debian/modules/http-lua/t/023-rewrite/tcp-socket.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/unix-socket.t b/debian/modules/http-lua/t/023-rewrite/unix-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/unix-socket.t rename to debian/modules/http-lua/t/023-rewrite/unix-socket.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t b/debian/modules/http-lua/t/023-rewrite/uthread-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-exec.t rename to debian/modules/http-lua/t/023-rewrite/uthread-exec.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t b/debian/modules/http-lua/t/023-rewrite/uthread-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-exit.t rename to debian/modules/http-lua/t/023-rewrite/uthread-exit.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t b/debian/modules/http-lua/t/023-rewrite/uthread-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-redirect.t rename to debian/modules/http-lua/t/023-rewrite/uthread-redirect.t diff --git a/debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t b/debian/modules/http-lua/t/023-rewrite/uthread-spawn.t similarity index 100% rename from debian/modules/nginx-lua/t/023-rewrite/uthread-spawn.t rename to debian/modules/http-lua/t/023-rewrite/uthread-spawn.t diff --git a/debian/modules/nginx-lua/t/024-access/auth.t b/debian/modules/http-lua/t/024-access/auth.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/auth.t rename to debian/modules/http-lua/t/024-access/auth.t diff --git a/debian/modules/nginx-lua/t/024-access/client-abort.t b/debian/modules/http-lua/t/024-access/client-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/client-abort.t rename to debian/modules/http-lua/t/024-access/client-abort.t diff --git a/debian/modules/nginx-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/exec.t rename to debian/modules/http-lua/t/024-access/exec.t diff --git a/debian/modules/nginx-lua/t/024-access/exit.t b/debian/modules/http-lua/t/024-access/exit.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/exit.t rename to debian/modules/http-lua/t/024-access/exit.t diff --git a/debian/modules/nginx-lua/t/024-access/mixed.t b/debian/modules/http-lua/t/024-access/mixed.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/mixed.t rename to debian/modules/http-lua/t/024-access/mixed.t diff --git a/debian/modules/nginx-lua/t/024-access/multi-capture.t b/debian/modules/http-lua/t/024-access/multi-capture.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/multi-capture.t rename to debian/modules/http-lua/t/024-access/multi-capture.t diff --git a/debian/modules/nginx-lua/t/024-access/on-abort.t b/debian/modules/http-lua/t/024-access/on-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/on-abort.t rename to debian/modules/http-lua/t/024-access/on-abort.t diff --git a/debian/modules/nginx-lua/t/024-access/redirect.t b/debian/modules/http-lua/t/024-access/redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/redirect.t rename to debian/modules/http-lua/t/024-access/redirect.t diff --git a/debian/modules/nginx-lua/t/024-access/req-body.t b/debian/modules/http-lua/t/024-access/req-body.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/req-body.t rename to debian/modules/http-lua/t/024-access/req-body.t diff --git a/debian/modules/nginx-lua/t/024-access/request_body.t b/debian/modules/http-lua/t/024-access/request_body.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/request_body.t rename to debian/modules/http-lua/t/024-access/request_body.t diff --git a/debian/modules/nginx-lua/t/024-access/sanity.t b/debian/modules/http-lua/t/024-access/sanity.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/sanity.t rename to debian/modules/http-lua/t/024-access/sanity.t diff --git a/debian/modules/nginx-lua/t/024-access/satisfy.t b/debian/modules/http-lua/t/024-access/satisfy.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/satisfy.t rename to debian/modules/http-lua/t/024-access/satisfy.t diff --git a/debian/modules/nginx-lua/t/024-access/sleep.t b/debian/modules/http-lua/t/024-access/sleep.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/sleep.t rename to debian/modules/http-lua/t/024-access/sleep.t diff --git a/debian/modules/nginx-lua/t/024-access/subrequest.t b/debian/modules/http-lua/t/024-access/subrequest.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/subrequest.t rename to debian/modules/http-lua/t/024-access/subrequest.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exec.t b/debian/modules/http-lua/t/024-access/uthread-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-exec.t rename to debian/modules/http-lua/t/024-access/uthread-exec.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-exit.t b/debian/modules/http-lua/t/024-access/uthread-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-exit.t rename to debian/modules/http-lua/t/024-access/uthread-exit.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-redirect.t b/debian/modules/http-lua/t/024-access/uthread-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-redirect.t rename to debian/modules/http-lua/t/024-access/uthread-redirect.t diff --git a/debian/modules/nginx-lua/t/024-access/uthread-spawn.t b/debian/modules/http-lua/t/024-access/uthread-spawn.t similarity index 100% rename from debian/modules/nginx-lua/t/024-access/uthread-spawn.t rename to debian/modules/http-lua/t/024-access/uthread-spawn.t diff --git a/debian/modules/nginx-lua/t/025-codecache.t b/debian/modules/http-lua/t/025-codecache.t similarity index 100% rename from debian/modules/nginx-lua/t/025-codecache.t rename to debian/modules/http-lua/t/025-codecache.t diff --git a/debian/modules/nginx-lua/t/026-mysql.t b/debian/modules/http-lua/t/026-mysql.t similarity index 100% rename from debian/modules/nginx-lua/t/026-mysql.t rename to debian/modules/http-lua/t/026-mysql.t diff --git a/debian/modules/nginx-lua/t/027-multi-capture.t b/debian/modules/http-lua/t/027-multi-capture.t similarity index 100% rename from debian/modules/nginx-lua/t/027-multi-capture.t rename to debian/modules/http-lua/t/027-multi-capture.t diff --git a/debian/modules/nginx-lua/t/028-req-header.t b/debian/modules/http-lua/t/028-req-header.t similarity index 100% rename from debian/modules/nginx-lua/t/028-req-header.t rename to debian/modules/http-lua/t/028-req-header.t diff --git a/debian/modules/nginx-lua/t/029-http-time.t b/debian/modules/http-lua/t/029-http-time.t similarity index 100% rename from debian/modules/nginx-lua/t/029-http-time.t rename to debian/modules/http-lua/t/029-http-time.t diff --git a/debian/modules/nginx-lua/t/030-uri-args.t b/debian/modules/http-lua/t/030-uri-args.t similarity index 100% rename from debian/modules/nginx-lua/t/030-uri-args.t rename to debian/modules/http-lua/t/030-uri-args.t diff --git a/debian/modules/nginx-lua/t/031-post-args.t b/debian/modules/http-lua/t/031-post-args.t similarity index 100% rename from debian/modules/nginx-lua/t/031-post-args.t rename to debian/modules/http-lua/t/031-post-args.t diff --git a/debian/modules/nginx-lua/t/032-iolist.t b/debian/modules/http-lua/t/032-iolist.t similarity index 100% rename from debian/modules/nginx-lua/t/032-iolist.t rename to debian/modules/http-lua/t/032-iolist.t diff --git a/debian/modules/nginx-lua/t/033-ctx.t b/debian/modules/http-lua/t/033-ctx.t similarity index 100% rename from debian/modules/nginx-lua/t/033-ctx.t rename to debian/modules/http-lua/t/033-ctx.t diff --git a/debian/modules/nginx-lua/t/034-match.t b/debian/modules/http-lua/t/034-match.t similarity index 100% rename from debian/modules/nginx-lua/t/034-match.t rename to debian/modules/http-lua/t/034-match.t diff --git a/debian/modules/nginx-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t similarity index 100% rename from debian/modules/nginx-lua/t/035-gmatch.t rename to debian/modules/http-lua/t/035-gmatch.t diff --git a/debian/modules/nginx-lua/t/036-sub.t b/debian/modules/http-lua/t/036-sub.t similarity index 100% rename from debian/modules/nginx-lua/t/036-sub.t rename to debian/modules/http-lua/t/036-sub.t diff --git a/debian/modules/nginx-lua/t/037-gsub.t b/debian/modules/http-lua/t/037-gsub.t similarity index 100% rename from debian/modules/nginx-lua/t/037-gsub.t rename to debian/modules/http-lua/t/037-gsub.t diff --git a/debian/modules/nginx-lua/t/038-match-o.t b/debian/modules/http-lua/t/038-match-o.t similarity index 100% rename from debian/modules/nginx-lua/t/038-match-o.t rename to debian/modules/http-lua/t/038-match-o.t diff --git a/debian/modules/nginx-lua/t/039-sub-o.t b/debian/modules/http-lua/t/039-sub-o.t similarity index 100% rename from debian/modules/nginx-lua/t/039-sub-o.t rename to debian/modules/http-lua/t/039-sub-o.t diff --git a/debian/modules/nginx-lua/t/040-gsub-o.t b/debian/modules/http-lua/t/040-gsub-o.t similarity index 100% rename from debian/modules/nginx-lua/t/040-gsub-o.t rename to debian/modules/http-lua/t/040-gsub-o.t diff --git a/debian/modules/nginx-lua/t/041-header-filter.t b/debian/modules/http-lua/t/041-header-filter.t similarity index 100% rename from debian/modules/nginx-lua/t/041-header-filter.t rename to debian/modules/http-lua/t/041-header-filter.t diff --git a/debian/modules/nginx-lua/t/042-crc32.t b/debian/modules/http-lua/t/042-crc32.t similarity index 100% rename from debian/modules/nginx-lua/t/042-crc32.t rename to debian/modules/http-lua/t/042-crc32.t diff --git a/debian/modules/nginx-lua/t/043-shdict.t b/debian/modules/http-lua/t/043-shdict.t similarity index 100% rename from debian/modules/nginx-lua/t/043-shdict.t rename to debian/modules/http-lua/t/043-shdict.t diff --git a/debian/modules/nginx-lua/t/044-req-body.t b/debian/modules/http-lua/t/044-req-body.t similarity index 100% rename from debian/modules/nginx-lua/t/044-req-body.t rename to debian/modules/http-lua/t/044-req-body.t diff --git a/debian/modules/nginx-lua/t/045-ngx-var.t b/debian/modules/http-lua/t/045-ngx-var.t similarity index 100% rename from debian/modules/nginx-lua/t/045-ngx-var.t rename to debian/modules/http-lua/t/045-ngx-var.t diff --git a/debian/modules/nginx-lua/t/046-hmac.t b/debian/modules/http-lua/t/046-hmac.t similarity index 100% rename from debian/modules/nginx-lua/t/046-hmac.t rename to debian/modules/http-lua/t/046-hmac.t diff --git a/debian/modules/nginx-lua/t/047-match-jit.t b/debian/modules/http-lua/t/047-match-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/047-match-jit.t rename to debian/modules/http-lua/t/047-match-jit.t diff --git a/debian/modules/nginx-lua/t/048-match-dfa.t b/debian/modules/http-lua/t/048-match-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/048-match-dfa.t rename to debian/modules/http-lua/t/048-match-dfa.t diff --git a/debian/modules/nginx-lua/t/049-gmatch-jit.t b/debian/modules/http-lua/t/049-gmatch-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/049-gmatch-jit.t rename to debian/modules/http-lua/t/049-gmatch-jit.t diff --git a/debian/modules/nginx-lua/t/050-gmatch-dfa.t b/debian/modules/http-lua/t/050-gmatch-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/050-gmatch-dfa.t rename to debian/modules/http-lua/t/050-gmatch-dfa.t diff --git a/debian/modules/nginx-lua/t/051-sub-jit.t b/debian/modules/http-lua/t/051-sub-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/051-sub-jit.t rename to debian/modules/http-lua/t/051-sub-jit.t diff --git a/debian/modules/nginx-lua/t/052-sub-dfa.t b/debian/modules/http-lua/t/052-sub-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/052-sub-dfa.t rename to debian/modules/http-lua/t/052-sub-dfa.t diff --git a/debian/modules/nginx-lua/t/053-gsub-jit.t b/debian/modules/http-lua/t/053-gsub-jit.t similarity index 100% rename from debian/modules/nginx-lua/t/053-gsub-jit.t rename to debian/modules/http-lua/t/053-gsub-jit.t diff --git a/debian/modules/nginx-lua/t/054-gsub-dfa.t b/debian/modules/http-lua/t/054-gsub-dfa.t similarity index 100% rename from debian/modules/nginx-lua/t/054-gsub-dfa.t rename to debian/modules/http-lua/t/054-gsub-dfa.t diff --git a/debian/modules/nginx-lua/t/055-subreq-vars.t b/debian/modules/http-lua/t/055-subreq-vars.t similarity index 100% rename from debian/modules/nginx-lua/t/055-subreq-vars.t rename to debian/modules/http-lua/t/055-subreq-vars.t diff --git a/debian/modules/nginx-lua/t/056-flush.t b/debian/modules/http-lua/t/056-flush.t similarity index 100% rename from debian/modules/nginx-lua/t/056-flush.t rename to debian/modules/http-lua/t/056-flush.t diff --git a/debian/modules/nginx-lua/t/057-flush-timeout.t b/debian/modules/http-lua/t/057-flush-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/057-flush-timeout.t rename to debian/modules/http-lua/t/057-flush-timeout.t diff --git a/debian/modules/nginx-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/058-tcp-socket.t rename to debian/modules/http-lua/t/058-tcp-socket.t diff --git a/debian/modules/nginx-lua/t/059-unix-socket.t b/debian/modules/http-lua/t/059-unix-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/059-unix-socket.t rename to debian/modules/http-lua/t/059-unix-socket.t diff --git a/debian/modules/nginx-lua/t/060-lua-memcached.t b/debian/modules/http-lua/t/060-lua-memcached.t similarity index 100% rename from debian/modules/nginx-lua/t/060-lua-memcached.t rename to debian/modules/http-lua/t/060-lua-memcached.t diff --git a/debian/modules/nginx-lua/t/061-lua-redis.t b/debian/modules/http-lua/t/061-lua-redis.t similarity index 100% rename from debian/modules/nginx-lua/t/061-lua-redis.t rename to debian/modules/http-lua/t/061-lua-redis.t diff --git a/debian/modules/nginx-lua/t/062-count.t b/debian/modules/http-lua/t/062-count.t similarity index 100% rename from debian/modules/nginx-lua/t/062-count.t rename to debian/modules/http-lua/t/062-count.t diff --git a/debian/modules/nginx-lua/t/063-abort.t b/debian/modules/http-lua/t/063-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/063-abort.t rename to debian/modules/http-lua/t/063-abort.t diff --git a/debian/modules/nginx-lua/t/064-pcall.t b/debian/modules/http-lua/t/064-pcall.t similarity index 100% rename from debian/modules/nginx-lua/t/064-pcall.t rename to debian/modules/http-lua/t/064-pcall.t diff --git a/debian/modules/nginx-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/065-tcp-socket-timeout.t rename to debian/modules/http-lua/t/065-tcp-socket-timeout.t diff --git a/debian/modules/nginx-lua/t/066-socket-receiveuntil.t b/debian/modules/http-lua/t/066-socket-receiveuntil.t similarity index 100% rename from debian/modules/nginx-lua/t/066-socket-receiveuntil.t rename to debian/modules/http-lua/t/066-socket-receiveuntil.t diff --git a/debian/modules/nginx-lua/t/067-req-socket.t b/debian/modules/http-lua/t/067-req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/067-req-socket.t rename to debian/modules/http-lua/t/067-req-socket.t diff --git a/debian/modules/nginx-lua/t/068-socket-keepalive.t b/debian/modules/http-lua/t/068-socket-keepalive.t similarity index 100% rename from debian/modules/nginx-lua/t/068-socket-keepalive.t rename to debian/modules/http-lua/t/068-socket-keepalive.t diff --git a/debian/modules/nginx-lua/t/069-null.t b/debian/modules/http-lua/t/069-null.t similarity index 100% rename from debian/modules/nginx-lua/t/069-null.t rename to debian/modules/http-lua/t/069-null.t diff --git a/debian/modules/nginx-lua/t/070-sha1.t b/debian/modules/http-lua/t/070-sha1.t similarity index 100% rename from debian/modules/nginx-lua/t/070-sha1.t rename to debian/modules/http-lua/t/070-sha1.t diff --git a/debian/modules/nginx-lua/t/071-idle-socket.t b/debian/modules/http-lua/t/071-idle-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/071-idle-socket.t rename to debian/modules/http-lua/t/071-idle-socket.t diff --git a/debian/modules/nginx-lua/t/072-conditional-get.t b/debian/modules/http-lua/t/072-conditional-get.t similarity index 100% rename from debian/modules/nginx-lua/t/072-conditional-get.t rename to debian/modules/http-lua/t/072-conditional-get.t diff --git a/debian/modules/nginx-lua/t/073-backtrace.t b/debian/modules/http-lua/t/073-backtrace.t similarity index 100% rename from debian/modules/nginx-lua/t/073-backtrace.t rename to debian/modules/http-lua/t/073-backtrace.t diff --git a/debian/modules/nginx-lua/t/074-prefix-var.t b/debian/modules/http-lua/t/074-prefix-var.t similarity index 100% rename from debian/modules/nginx-lua/t/074-prefix-var.t rename to debian/modules/http-lua/t/074-prefix-var.t diff --git a/debian/modules/nginx-lua/t/075-logby.t b/debian/modules/http-lua/t/075-logby.t similarity index 100% rename from debian/modules/nginx-lua/t/075-logby.t rename to debian/modules/http-lua/t/075-logby.t diff --git a/debian/modules/nginx-lua/t/076-no-postpone.t b/debian/modules/http-lua/t/076-no-postpone.t similarity index 100% rename from debian/modules/nginx-lua/t/076-no-postpone.t rename to debian/modules/http-lua/t/076-no-postpone.t diff --git a/debian/modules/nginx-lua/t/077-sleep.t b/debian/modules/http-lua/t/077-sleep.t similarity index 100% rename from debian/modules/nginx-lua/t/077-sleep.t rename to debian/modules/http-lua/t/077-sleep.t diff --git a/debian/modules/nginx-lua/t/078-hup-vars.t b/debian/modules/http-lua/t/078-hup-vars.t similarity index 100% rename from debian/modules/nginx-lua/t/078-hup-vars.t rename to debian/modules/http-lua/t/078-hup-vars.t diff --git a/debian/modules/nginx-lua/t/079-unused-directives.t b/debian/modules/http-lua/t/079-unused-directives.t similarity index 100% rename from debian/modules/nginx-lua/t/079-unused-directives.t rename to debian/modules/http-lua/t/079-unused-directives.t diff --git a/debian/modules/nginx-lua/t/080-hup-shdict.t b/debian/modules/http-lua/t/080-hup-shdict.t similarity index 100% rename from debian/modules/nginx-lua/t/080-hup-shdict.t rename to debian/modules/http-lua/t/080-hup-shdict.t diff --git a/debian/modules/nginx-lua/t/081-bytecode.t b/debian/modules/http-lua/t/081-bytecode.t similarity index 100% rename from debian/modules/nginx-lua/t/081-bytecode.t rename to debian/modules/http-lua/t/081-bytecode.t diff --git a/debian/modules/nginx-lua/t/082-body-filter.t b/debian/modules/http-lua/t/082-body-filter.t similarity index 100% rename from debian/modules/nginx-lua/t/082-body-filter.t rename to debian/modules/http-lua/t/082-body-filter.t diff --git a/debian/modules/nginx-lua/t/083-bad-sock-self.t b/debian/modules/http-lua/t/083-bad-sock-self.t similarity index 100% rename from debian/modules/nginx-lua/t/083-bad-sock-self.t rename to debian/modules/http-lua/t/083-bad-sock-self.t diff --git a/debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t b/debian/modules/http-lua/t/084-inclusive-receiveuntil.t similarity index 100% rename from debian/modules/nginx-lua/t/084-inclusive-receiveuntil.t rename to debian/modules/http-lua/t/084-inclusive-receiveuntil.t diff --git a/debian/modules/nginx-lua/t/085-if.t b/debian/modules/http-lua/t/085-if.t similarity index 100% rename from debian/modules/nginx-lua/t/085-if.t rename to debian/modules/http-lua/t/085-if.t diff --git a/debian/modules/nginx-lua/t/086-init-by.t b/debian/modules/http-lua/t/086-init-by.t similarity index 100% rename from debian/modules/nginx-lua/t/086-init-by.t rename to debian/modules/http-lua/t/086-init-by.t diff --git a/debian/modules/nginx-lua/t/087-udp-socket.t b/debian/modules/http-lua/t/087-udp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/087-udp-socket.t rename to debian/modules/http-lua/t/087-udp-socket.t diff --git a/debian/modules/nginx-lua/t/088-req-method.t b/debian/modules/http-lua/t/088-req-method.t similarity index 100% rename from debian/modules/nginx-lua/t/088-req-method.t rename to debian/modules/http-lua/t/088-req-method.t diff --git a/debian/modules/nginx-lua/t/089-phase.t b/debian/modules/http-lua/t/089-phase.t similarity index 100% rename from debian/modules/nginx-lua/t/089-phase.t rename to debian/modules/http-lua/t/089-phase.t diff --git a/debian/modules/nginx-lua/t/090-log-socket-errors.t b/debian/modules/http-lua/t/090-log-socket-errors.t similarity index 100% rename from debian/modules/nginx-lua/t/090-log-socket-errors.t rename to debian/modules/http-lua/t/090-log-socket-errors.t diff --git a/debian/modules/nginx-lua/t/091-coroutine.t b/debian/modules/http-lua/t/091-coroutine.t similarity index 100% rename from debian/modules/nginx-lua/t/091-coroutine.t rename to debian/modules/http-lua/t/091-coroutine.t diff --git a/debian/modules/nginx-lua/t/092-eof.t b/debian/modules/http-lua/t/092-eof.t similarity index 100% rename from debian/modules/nginx-lua/t/092-eof.t rename to debian/modules/http-lua/t/092-eof.t diff --git a/debian/modules/nginx-lua/t/093-uthread-spawn.t b/debian/modules/http-lua/t/093-uthread-spawn.t similarity index 100% rename from debian/modules/nginx-lua/t/093-uthread-spawn.t rename to debian/modules/http-lua/t/093-uthread-spawn.t diff --git a/debian/modules/nginx-lua/t/094-uthread-exit.t b/debian/modules/http-lua/t/094-uthread-exit.t similarity index 100% rename from debian/modules/nginx-lua/t/094-uthread-exit.t rename to debian/modules/http-lua/t/094-uthread-exit.t diff --git a/debian/modules/nginx-lua/t/095-uthread-exec.t b/debian/modules/http-lua/t/095-uthread-exec.t similarity index 100% rename from debian/modules/nginx-lua/t/095-uthread-exec.t rename to debian/modules/http-lua/t/095-uthread-exec.t diff --git a/debian/modules/nginx-lua/t/096-uthread-redirect.t b/debian/modules/http-lua/t/096-uthread-redirect.t similarity index 100% rename from debian/modules/nginx-lua/t/096-uthread-redirect.t rename to debian/modules/http-lua/t/096-uthread-redirect.t diff --git a/debian/modules/nginx-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t similarity index 100% rename from debian/modules/nginx-lua/t/097-uthread-rewrite.t rename to debian/modules/http-lua/t/097-uthread-rewrite.t diff --git a/debian/modules/nginx-lua/t/098-uthread-wait.t b/debian/modules/http-lua/t/098-uthread-wait.t similarity index 100% rename from debian/modules/nginx-lua/t/098-uthread-wait.t rename to debian/modules/http-lua/t/098-uthread-wait.t diff --git a/debian/modules/nginx-lua/t/099-c-api.t b/debian/modules/http-lua/t/099-c-api.t similarity index 100% rename from debian/modules/nginx-lua/t/099-c-api.t rename to debian/modules/http-lua/t/099-c-api.t diff --git a/debian/modules/nginx-lua/t/100-client-abort.t b/debian/modules/http-lua/t/100-client-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/100-client-abort.t rename to debian/modules/http-lua/t/100-client-abort.t diff --git a/debian/modules/nginx-lua/t/101-on-abort.t b/debian/modules/http-lua/t/101-on-abort.t similarity index 100% rename from debian/modules/nginx-lua/t/101-on-abort.t rename to debian/modules/http-lua/t/101-on-abort.t diff --git a/debian/modules/nginx-lua/t/102-req-start-time.t b/debian/modules/http-lua/t/102-req-start-time.t similarity index 100% rename from debian/modules/nginx-lua/t/102-req-start-time.t rename to debian/modules/http-lua/t/102-req-start-time.t diff --git a/debian/modules/nginx-lua/t/103-req-http-ver.t b/debian/modules/http-lua/t/103-req-http-ver.t similarity index 100% rename from debian/modules/nginx-lua/t/103-req-http-ver.t rename to debian/modules/http-lua/t/103-req-http-ver.t diff --git a/debian/modules/nginx-lua/t/104-req-raw-header.t b/debian/modules/http-lua/t/104-req-raw-header.t similarity index 100% rename from debian/modules/nginx-lua/t/104-req-raw-header.t rename to debian/modules/http-lua/t/104-req-raw-header.t diff --git a/debian/modules/nginx-lua/t/105-pressure.t b/debian/modules/http-lua/t/105-pressure.t similarity index 100% rename from debian/modules/nginx-lua/t/105-pressure.t rename to debian/modules/http-lua/t/105-pressure.t diff --git a/debian/modules/nginx-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t similarity index 100% rename from debian/modules/nginx-lua/t/106-timer.t rename to debian/modules/http-lua/t/106-timer.t diff --git a/debian/modules/nginx-lua/t/107-timer-errors.t b/debian/modules/http-lua/t/107-timer-errors.t similarity index 100% rename from debian/modules/nginx-lua/t/107-timer-errors.t rename to debian/modules/http-lua/t/107-timer-errors.t diff --git a/debian/modules/nginx-lua/t/108-timer-safe.t b/debian/modules/http-lua/t/108-timer-safe.t similarity index 100% rename from debian/modules/nginx-lua/t/108-timer-safe.t rename to debian/modules/http-lua/t/108-timer-safe.t diff --git a/debian/modules/nginx-lua/t/109-timer-hup.t b/debian/modules/http-lua/t/109-timer-hup.t similarity index 100% rename from debian/modules/nginx-lua/t/109-timer-hup.t rename to debian/modules/http-lua/t/109-timer-hup.t diff --git a/debian/modules/nginx-lua/t/110-etag.t b/debian/modules/http-lua/t/110-etag.t similarity index 100% rename from debian/modules/nginx-lua/t/110-etag.t rename to debian/modules/http-lua/t/110-etag.t diff --git a/debian/modules/nginx-lua/t/111-req-header-ua.t b/debian/modules/http-lua/t/111-req-header-ua.t similarity index 100% rename from debian/modules/nginx-lua/t/111-req-header-ua.t rename to debian/modules/http-lua/t/111-req-header-ua.t diff --git a/debian/modules/nginx-lua/t/112-req-header-conn.t b/debian/modules/http-lua/t/112-req-header-conn.t similarity index 100% rename from debian/modules/nginx-lua/t/112-req-header-conn.t rename to debian/modules/http-lua/t/112-req-header-conn.t diff --git a/debian/modules/nginx-lua/t/113-req-header-cookie.t b/debian/modules/http-lua/t/113-req-header-cookie.t similarity index 100% rename from debian/modules/nginx-lua/t/113-req-header-cookie.t rename to debian/modules/http-lua/t/113-req-header-cookie.t diff --git a/debian/modules/nginx-lua/t/114-config.t b/debian/modules/http-lua/t/114-config.t similarity index 100% rename from debian/modules/nginx-lua/t/114-config.t rename to debian/modules/http-lua/t/114-config.t diff --git a/debian/modules/nginx-lua/t/115-quote-sql-str.t b/debian/modules/http-lua/t/115-quote-sql-str.t similarity index 100% rename from debian/modules/nginx-lua/t/115-quote-sql-str.t rename to debian/modules/http-lua/t/115-quote-sql-str.t diff --git a/debian/modules/nginx-lua/t/116-raw-req-socket.t b/debian/modules/http-lua/t/116-raw-req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/116-raw-req-socket.t rename to debian/modules/http-lua/t/116-raw-req-socket.t diff --git a/debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t b/debian/modules/http-lua/t/117-raw-req-socket-timeout.t similarity index 100% rename from debian/modules/nginx-lua/t/117-raw-req-socket-timeout.t rename to debian/modules/http-lua/t/117-raw-req-socket-timeout.t diff --git a/debian/modules/nginx-lua/t/118-use-default-type.t b/debian/modules/http-lua/t/118-use-default-type.t similarity index 100% rename from debian/modules/nginx-lua/t/118-use-default-type.t rename to debian/modules/http-lua/t/118-use-default-type.t diff --git a/debian/modules/nginx-lua/t/119-config-prefix.t b/debian/modules/http-lua/t/119-config-prefix.t similarity index 100% rename from debian/modules/nginx-lua/t/119-config-prefix.t rename to debian/modules/http-lua/t/119-config-prefix.t diff --git a/debian/modules/nginx-lua/t/120-re-find.t b/debian/modules/http-lua/t/120-re-find.t similarity index 100% rename from debian/modules/nginx-lua/t/120-re-find.t rename to debian/modules/http-lua/t/120-re-find.t diff --git a/debian/modules/nginx-lua/t/121-version.t b/debian/modules/http-lua/t/121-version.t similarity index 100% rename from debian/modules/nginx-lua/t/121-version.t rename to debian/modules/http-lua/t/121-version.t diff --git a/debian/modules/nginx-lua/t/122-worker.t b/debian/modules/http-lua/t/122-worker.t similarity index 100% rename from debian/modules/nginx-lua/t/122-worker.t rename to debian/modules/http-lua/t/122-worker.t diff --git a/debian/modules/nginx-lua/t/123-lua-path.t b/debian/modules/http-lua/t/123-lua-path.t similarity index 100% rename from debian/modules/nginx-lua/t/123-lua-path.t rename to debian/modules/http-lua/t/123-lua-path.t diff --git a/debian/modules/nginx-lua/t/124-init-worker.t b/debian/modules/http-lua/t/124-init-worker.t similarity index 100% rename from debian/modules/nginx-lua/t/124-init-worker.t rename to debian/modules/http-lua/t/124-init-worker.t diff --git a/debian/modules/nginx-lua/t/125-configure-args.t b/debian/modules/http-lua/t/125-configure-args.t similarity index 100% rename from debian/modules/nginx-lua/t/125-configure-args.t rename to debian/modules/http-lua/t/125-configure-args.t diff --git a/debian/modules/nginx-lua/t/126-shdict-frag.t b/debian/modules/http-lua/t/126-shdict-frag.t similarity index 100% rename from debian/modules/nginx-lua/t/126-shdict-frag.t rename to debian/modules/http-lua/t/126-shdict-frag.t diff --git a/debian/modules/nginx-lua/t/127-uthread-kill.t b/debian/modules/http-lua/t/127-uthread-kill.t similarity index 100% rename from debian/modules/nginx-lua/t/127-uthread-kill.t rename to debian/modules/http-lua/t/127-uthread-kill.t diff --git a/debian/modules/nginx-lua/t/128-duplex-tcp-socket.t b/debian/modules/http-lua/t/128-duplex-tcp-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/128-duplex-tcp-socket.t rename to debian/modules/http-lua/t/128-duplex-tcp-socket.t diff --git a/debian/modules/nginx-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/129-ssl-socket.t rename to debian/modules/http-lua/t/129-ssl-socket.t diff --git a/debian/modules/nginx-lua/t/130-internal-api.t b/debian/modules/http-lua/t/130-internal-api.t similarity index 100% rename from debian/modules/nginx-lua/t/130-internal-api.t rename to debian/modules/http-lua/t/130-internal-api.t diff --git a/debian/modules/nginx-lua/t/131-duplex-req-socket.t b/debian/modules/http-lua/t/131-duplex-req-socket.t similarity index 100% rename from debian/modules/nginx-lua/t/131-duplex-req-socket.t rename to debian/modules/http-lua/t/131-duplex-req-socket.t diff --git a/debian/modules/nginx-lua/t/132-lua-blocks.t b/debian/modules/http-lua/t/132-lua-blocks.t similarity index 100% rename from debian/modules/nginx-lua/t/132-lua-blocks.t rename to debian/modules/http-lua/t/132-lua-blocks.t diff --git a/debian/modules/nginx-lua/t/133-worker-count.t b/debian/modules/http-lua/t/133-worker-count.t similarity index 100% rename from debian/modules/nginx-lua/t/133-worker-count.t rename to debian/modules/http-lua/t/133-worker-count.t diff --git a/debian/modules/nginx-lua/t/134-worker-count-5.t b/debian/modules/http-lua/t/134-worker-count-5.t similarity index 100% rename from debian/modules/nginx-lua/t/134-worker-count-5.t rename to debian/modules/http-lua/t/134-worker-count-5.t diff --git a/debian/modules/nginx-lua/t/135-worker-id.t b/debian/modules/http-lua/t/135-worker-id.t similarity index 100% rename from debian/modules/nginx-lua/t/135-worker-id.t rename to debian/modules/http-lua/t/135-worker-id.t diff --git a/debian/modules/nginx-lua/t/136-timer-counts.t b/debian/modules/http-lua/t/136-timer-counts.t similarity index 100% rename from debian/modules/nginx-lua/t/136-timer-counts.t rename to debian/modules/http-lua/t/136-timer-counts.t diff --git a/debian/modules/nginx-lua/t/137-req-misc.t b/debian/modules/http-lua/t/137-req-misc.t similarity index 100% rename from debian/modules/nginx-lua/t/137-req-misc.t rename to debian/modules/http-lua/t/137-req-misc.t diff --git a/debian/modules/nginx-lua/t/138-balancer.t b/debian/modules/http-lua/t/138-balancer.t similarity index 100% rename from debian/modules/nginx-lua/t/138-balancer.t rename to debian/modules/http-lua/t/138-balancer.t diff --git a/debian/modules/nginx-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t similarity index 100% rename from debian/modules/nginx-lua/t/139-ssl-cert-by.t rename to debian/modules/http-lua/t/139-ssl-cert-by.t diff --git a/debian/modules/nginx-lua/t/140-ssl-c-api.t b/debian/modules/http-lua/t/140-ssl-c-api.t similarity index 100% rename from debian/modules/nginx-lua/t/140-ssl-c-api.t rename to debian/modules/http-lua/t/140-ssl-c-api.t diff --git a/debian/modules/nginx-lua/t/141-luajit.t b/debian/modules/http-lua/t/141-luajit.t similarity index 100% rename from debian/modules/nginx-lua/t/141-luajit.t rename to debian/modules/http-lua/t/141-luajit.t diff --git a/debian/modules/nginx-lua/t/142-ssl-session-store.t b/debian/modules/http-lua/t/142-ssl-session-store.t similarity index 100% rename from debian/modules/nginx-lua/t/142-ssl-session-store.t rename to debian/modules/http-lua/t/142-ssl-session-store.t diff --git a/debian/modules/nginx-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t similarity index 100% rename from debian/modules/nginx-lua/t/143-ssl-session-fetch.t rename to debian/modules/http-lua/t/143-ssl-session-fetch.t diff --git a/debian/modules/nginx-lua/t/144-shdict-incr-init.t b/debian/modules/http-lua/t/144-shdict-incr-init.t similarity index 100% rename from debian/modules/nginx-lua/t/144-shdict-incr-init.t rename to debian/modules/http-lua/t/144-shdict-incr-init.t diff --git a/debian/modules/nginx-lua/t/145-shdict-list.t b/debian/modules/http-lua/t/145-shdict-list.t similarity index 100% rename from debian/modules/nginx-lua/t/145-shdict-list.t rename to debian/modules/http-lua/t/145-shdict-list.t diff --git a/debian/modules/nginx-lua/t/146-malloc-trim.t b/debian/modules/http-lua/t/146-malloc-trim.t similarity index 100% rename from debian/modules/nginx-lua/t/146-malloc-trim.t rename to debian/modules/http-lua/t/146-malloc-trim.t diff --git a/debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t similarity index 100% rename from debian/modules/nginx-lua/t/147-tcp-socket-timeouts.t rename to debian/modules/http-lua/t/147-tcp-socket-timeouts.t diff --git a/debian/modules/nginx-lua/t/148-fake-shm-zone.t b/debian/modules/http-lua/t/148-fake-shm-zone.t similarity index 100% rename from debian/modules/nginx-lua/t/148-fake-shm-zone.t rename to debian/modules/http-lua/t/148-fake-shm-zone.t diff --git a/debian/modules/nginx-lua/t/149-hup-fake-shm-zone.t b/debian/modules/http-lua/t/149-hup-fake-shm-zone.t similarity index 100% rename from debian/modules/nginx-lua/t/149-hup-fake-shm-zone.t rename to debian/modules/http-lua/t/149-hup-fake-shm-zone.t diff --git a/debian/modules/nginx-lua/t/150-fake-delayed-load.t b/debian/modules/http-lua/t/150-fake-delayed-load.t similarity index 100% rename from debian/modules/nginx-lua/t/150-fake-delayed-load.t rename to debian/modules/http-lua/t/150-fake-delayed-load.t diff --git a/debian/modules/nginx-lua/t/151-initby-hup.t b/debian/modules/http-lua/t/151-initby-hup.t similarity index 100% rename from debian/modules/nginx-lua/t/151-initby-hup.t rename to debian/modules/http-lua/t/151-initby-hup.t diff --git a/debian/modules/nginx-lua/t/152-timer-every.t b/debian/modules/http-lua/t/152-timer-every.t similarity index 100% rename from debian/modules/nginx-lua/t/152-timer-every.t rename to debian/modules/http-lua/t/152-timer-every.t diff --git a/debian/modules/nginx-lua/t/153-semaphore-hup.t b/debian/modules/http-lua/t/153-semaphore-hup.t similarity index 100% rename from debian/modules/nginx-lua/t/153-semaphore-hup.t rename to debian/modules/http-lua/t/153-semaphore-hup.t diff --git a/debian/modules/nginx-lua/t/154-semaphore.t b/debian/modules/http-lua/t/154-semaphore.t similarity index 100% rename from debian/modules/nginx-lua/t/154-semaphore.t rename to debian/modules/http-lua/t/154-semaphore.t diff --git a/debian/modules/nginx-lua/t/StapThread.pm b/debian/modules/http-lua/t/StapThread.pm similarity index 100% rename from debian/modules/nginx-lua/t/StapThread.pm rename to debian/modules/http-lua/t/StapThread.pm diff --git a/debian/modules/nginx-lua/t/cert/comodo-ca.crt b/debian/modules/http-lua/t/cert/comodo-ca.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/comodo-ca.crt rename to debian/modules/http-lua/t/cert/comodo-ca.crt diff --git a/debian/modules/nginx-lua/t/cert/equifax.crt b/debian/modules/http-lua/t/cert/equifax.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/equifax.crt rename to debian/modules/http-lua/t/cert/equifax.crt diff --git a/debian/modules/nginx-lua/t/cert/test.crl b/debian/modules/http-lua/t/cert/test.crl similarity index 100% rename from debian/modules/nginx-lua/t/cert/test.crl rename to debian/modules/http-lua/t/cert/test.crl diff --git a/debian/modules/nginx-lua/t/cert/test.crt b/debian/modules/http-lua/t/cert/test.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/test.crt rename to debian/modules/http-lua/t/cert/test.crt diff --git a/debian/modules/nginx-lua/t/cert/test.key b/debian/modules/http-lua/t/cert/test.key similarity index 100% rename from debian/modules/nginx-lua/t/cert/test.key rename to debian/modules/http-lua/t/cert/test.key diff --git a/debian/modules/nginx-lua/t/cert/test2.crt b/debian/modules/http-lua/t/cert/test2.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/test2.crt rename to debian/modules/http-lua/t/cert/test2.crt diff --git a/debian/modules/nginx-lua/t/cert/test2.key b/debian/modules/http-lua/t/cert/test2.key similarity index 100% rename from debian/modules/nginx-lua/t/cert/test2.key rename to debian/modules/http-lua/t/cert/test2.key diff --git a/debian/modules/nginx-lua/t/cert/test_ecdsa.crt b/debian/modules/http-lua/t/cert/test_ecdsa.crt similarity index 100% rename from debian/modules/nginx-lua/t/cert/test_ecdsa.crt rename to debian/modules/http-lua/t/cert/test_ecdsa.crt diff --git a/debian/modules/nginx-lua/t/cert/test_ecdsa.key b/debian/modules/http-lua/t/cert/test_ecdsa.key similarity index 100% rename from debian/modules/nginx-lua/t/cert/test_ecdsa.key rename to debian/modules/http-lua/t/cert/test_ecdsa.key diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/config b/debian/modules/http-lua/t/data/fake-delayed-load-module/config similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-delayed-load-module/config rename to debian/modules/http-lua/t/data/fake-delayed-load-module/config diff --git a/debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c b/debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c rename to debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c diff --git a/debian/modules/nginx-lua/t/data/fake-module/config b/debian/modules/http-lua/t/data/fake-module/config similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-module/config rename to debian/modules/http-lua/t/data/fake-module/config diff --git a/debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c b/debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-module/ngx_http_fake_module.c rename to debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c diff --git a/debian/modules/nginx-lua/t/data/fake-shm-module/config b/debian/modules/http-lua/t/data/fake-shm-module/config similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-shm-module/config rename to debian/modules/http-lua/t/data/fake-shm-module/config diff --git a/debian/modules/nginx-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c b/debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c similarity index 100% rename from debian/modules/nginx-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c rename to debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c diff --git a/debian/modules/nginx-lua/t/lib/CRC32.lua b/debian/modules/http-lua/t/lib/CRC32.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/CRC32.lua rename to debian/modules/http-lua/t/lib/CRC32.lua diff --git a/debian/modules/nginx-lua/t/lib/Memcached.lua b/debian/modules/http-lua/t/lib/Memcached.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/Memcached.lua rename to debian/modules/http-lua/t/lib/Memcached.lua diff --git a/debian/modules/nginx-lua/t/lib/Redis.lua b/debian/modules/http-lua/t/lib/Redis.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/Redis.lua rename to debian/modules/http-lua/t/lib/Redis.lua diff --git a/debian/modules/nginx-lua/t/lib/ljson.lua b/debian/modules/http-lua/t/lib/ljson.lua similarity index 100% rename from debian/modules/nginx-lua/t/lib/ljson.lua rename to debian/modules/http-lua/t/lib/ljson.lua diff --git a/debian/modules/nginx-lua/tapset/ngx_lua.stp b/debian/modules/http-lua/tapset/ngx_lua.stp similarity index 100% rename from debian/modules/nginx-lua/tapset/ngx_lua.stp rename to debian/modules/http-lua/tapset/ngx_lua.stp diff --git a/debian/modules/nginx-lua/util/build.sh b/debian/modules/http-lua/util/build.sh similarity index 100% rename from debian/modules/nginx-lua/util/build.sh rename to debian/modules/http-lua/util/build.sh diff --git a/debian/modules/nginx-lua/util/fix-comments b/debian/modules/http-lua/util/fix-comments similarity index 100% rename from debian/modules/nginx-lua/util/fix-comments rename to debian/modules/http-lua/util/fix-comments diff --git a/debian/modules/nginx-lua/util/gen-lexer-c b/debian/modules/http-lua/util/gen-lexer-c similarity index 100% rename from debian/modules/nginx-lua/util/gen-lexer-c rename to debian/modules/http-lua/util/gen-lexer-c diff --git a/debian/modules/nginx-lua/util/ngx-links b/debian/modules/http-lua/util/ngx-links similarity index 100% rename from debian/modules/nginx-lua/util/ngx-links rename to debian/modules/http-lua/util/ngx-links diff --git a/debian/modules/nginx-lua/util/releng b/debian/modules/http-lua/util/releng similarity index 100% rename from debian/modules/nginx-lua/util/releng rename to debian/modules/http-lua/util/releng diff --git a/debian/modules/nginx-lua/util/retab b/debian/modules/http-lua/util/retab similarity index 100% rename from debian/modules/nginx-lua/util/retab rename to debian/modules/http-lua/util/retab diff --git a/debian/modules/nginx-lua/util/revim b/debian/modules/http-lua/util/revim similarity index 100% rename from debian/modules/nginx-lua/util/revim rename to debian/modules/http-lua/util/revim diff --git a/debian/modules/nginx-lua/util/run_test.sh b/debian/modules/http-lua/util/run_test.sh similarity index 100% rename from debian/modules/nginx-lua/util/run_test.sh rename to debian/modules/http-lua/util/run_test.sh diff --git a/debian/modules/nginx-lua/util/update-readme.sh b/debian/modules/http-lua/util/update-readme.sh similarity index 100% rename from debian/modules/nginx-lua/util/update-readme.sh rename to debian/modules/http-lua/util/update-readme.sh diff --git a/debian/modules/nginx-lua/valgrind.suppress b/debian/modules/http-lua/valgrind.suppress similarity index 100% rename from debian/modules/nginx-lua/valgrind.suppress rename to debian/modules/http-lua/valgrind.suppress diff --git a/debian/modules/nginx-development-kit/LICENSE b/debian/modules/http-ndk/LICENSE similarity index 100% rename from debian/modules/nginx-development-kit/LICENSE rename to debian/modules/http-ndk/LICENSE diff --git a/debian/modules/nginx-development-kit/README.md b/debian/modules/http-ndk/README.md similarity index 100% rename from debian/modules/nginx-development-kit/README.md rename to debian/modules/http-ndk/README.md diff --git a/debian/modules/nginx-development-kit/README_AUTO_LIB b/debian/modules/http-ndk/README_AUTO_LIB similarity index 100% rename from debian/modules/nginx-development-kit/README_AUTO_LIB rename to debian/modules/http-ndk/README_AUTO_LIB diff --git a/debian/modules/nginx-development-kit/TODO b/debian/modules/http-ndk/TODO similarity index 100% rename from debian/modules/nginx-development-kit/TODO rename to debian/modules/http-ndk/TODO diff --git a/debian/modules/nginx-development-kit/auto/actions/array b/debian/modules/http-ndk/auto/actions/array similarity index 100% rename from debian/modules/nginx-development-kit/auto/actions/array rename to debian/modules/http-ndk/auto/actions/array diff --git a/debian/modules/nginx-development-kit/auto/actions/palloc b/debian/modules/http-ndk/auto/actions/palloc similarity index 100% rename from debian/modules/nginx-development-kit/auto/actions/palloc rename to debian/modules/http-ndk/auto/actions/palloc diff --git a/debian/modules/nginx-development-kit/auto/build b/debian/modules/http-ndk/auto/build similarity index 100% rename from debian/modules/nginx-development-kit/auto/build rename to debian/modules/http-ndk/auto/build diff --git a/debian/modules/nginx-development-kit/auto/data/action_replacements b/debian/modules/http-ndk/auto/data/action_replacements similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/action_replacements rename to debian/modules/http-ndk/auto/data/action_replacements diff --git a/debian/modules/nginx-development-kit/auto/data/action_types b/debian/modules/http-ndk/auto/data/action_types similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/action_types rename to debian/modules/http-ndk/auto/data/action_types diff --git a/debian/modules/nginx-development-kit/auto/data/conf_args b/debian/modules/http-ndk/auto/data/conf_args similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/conf_args rename to debian/modules/http-ndk/auto/data/conf_args diff --git a/debian/modules/nginx-development-kit/auto/data/conf_locs b/debian/modules/http-ndk/auto/data/conf_locs similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/conf_locs rename to debian/modules/http-ndk/auto/data/conf_locs diff --git a/debian/modules/nginx-development-kit/auto/data/conf_macros b/debian/modules/http-ndk/auto/data/conf_macros similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/conf_macros rename to debian/modules/http-ndk/auto/data/conf_macros diff --git a/debian/modules/nginx-development-kit/auto/data/contexts b/debian/modules/http-ndk/auto/data/contexts similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/contexts rename to debian/modules/http-ndk/auto/data/contexts diff --git a/debian/modules/nginx-development-kit/auto/data/header_files b/debian/modules/http-ndk/auto/data/header_files similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/header_files rename to debian/modules/http-ndk/auto/data/header_files diff --git a/debian/modules/nginx-development-kit/auto/data/headers b/debian/modules/http-ndk/auto/data/headers similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/headers rename to debian/modules/http-ndk/auto/data/headers diff --git a/debian/modules/nginx-development-kit/auto/data/module_dependencies b/debian/modules/http-ndk/auto/data/module_dependencies similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/module_dependencies rename to debian/modules/http-ndk/auto/data/module_dependencies diff --git a/debian/modules/nginx-development-kit/auto/data/modules_optional b/debian/modules/http-ndk/auto/data/modules_optional similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/modules_optional rename to debian/modules/http-ndk/auto/data/modules_optional diff --git a/debian/modules/nginx-development-kit/auto/data/prefixes b/debian/modules/http-ndk/auto/data/prefixes similarity index 100% rename from debian/modules/nginx-development-kit/auto/data/prefixes rename to debian/modules/http-ndk/auto/data/prefixes diff --git a/debian/modules/nginx-development-kit/auto/src/array.h b/debian/modules/http-ndk/auto/src/array.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/array.h rename to debian/modules/http-ndk/auto/src/array.h diff --git a/debian/modules/nginx-development-kit/auto/src/conf_cmd_basic.h b/debian/modules/http-ndk/auto/src/conf_cmd_basic.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/conf_cmd_basic.h rename to debian/modules/http-ndk/auto/src/conf_cmd_basic.h diff --git a/debian/modules/nginx-development-kit/auto/src/conf_merge.h b/debian/modules/http-ndk/auto/src/conf_merge.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/conf_merge.h rename to debian/modules/http-ndk/auto/src/conf_merge.h diff --git a/debian/modules/nginx-development-kit/auto/src/palloc.h b/debian/modules/http-ndk/auto/src/palloc.h similarity index 100% rename from debian/modules/nginx-development-kit/auto/src/palloc.h rename to debian/modules/http-ndk/auto/src/palloc.h diff --git a/debian/modules/nginx-development-kit/auto/text/autogen b/debian/modules/http-ndk/auto/text/autogen similarity index 100% rename from debian/modules/nginx-development-kit/auto/text/autogen rename to debian/modules/http-ndk/auto/text/autogen diff --git a/debian/modules/nginx-development-kit/config b/debian/modules/http-ndk/config similarity index 100% rename from debian/modules/nginx-development-kit/config rename to debian/modules/http-ndk/config diff --git a/debian/modules/nginx-development-kit/docs/core/action_macros b/debian/modules/http-ndk/docs/core/action_macros similarity index 100% rename from debian/modules/nginx-development-kit/docs/core/action_macros rename to debian/modules/http-ndk/docs/core/action_macros diff --git a/debian/modules/nginx-development-kit/docs/core/conf_cmds b/debian/modules/http-ndk/docs/core/conf_cmds similarity index 100% rename from debian/modules/nginx-development-kit/docs/core/conf_cmds rename to debian/modules/http-ndk/docs/core/conf_cmds diff --git a/debian/modules/nginx-development-kit/docs/modules/set_var b/debian/modules/http-ndk/docs/modules/set_var similarity index 100% rename from debian/modules/nginx-development-kit/docs/modules/set_var rename to debian/modules/http-ndk/docs/modules/set_var diff --git a/debian/modules/nginx-development-kit/docs/patches/more_logging_info b/debian/modules/http-ndk/docs/patches/more_logging_info similarity index 100% rename from debian/modules/nginx-development-kit/docs/patches/more_logging_info rename to debian/modules/http-ndk/docs/patches/more_logging_info diff --git a/debian/modules/nginx-development-kit/docs/upstream/list b/debian/modules/http-ndk/docs/upstream/list similarity index 100% rename from debian/modules/nginx-development-kit/docs/upstream/list rename to debian/modules/http-ndk/docs/upstream/list diff --git a/debian/modules/nginx-development-kit/examples/README b/debian/modules/http-ndk/examples/README similarity index 100% rename from debian/modules/nginx-development-kit/examples/README rename to debian/modules/http-ndk/examples/README diff --git a/debian/modules/nginx-development-kit/examples/http/set_var/config b/debian/modules/http-ndk/examples/http/set_var/config similarity index 100% rename from debian/modules/nginx-development-kit/examples/http/set_var/config rename to debian/modules/http-ndk/examples/http/set_var/config diff --git a/debian/modules/nginx-development-kit/examples/http/set_var/ngx_http_set_var_examples_module.c b/debian/modules/http-ndk/examples/http/set_var/ngx_http_set_var_examples_module.c similarity index 100% rename from debian/modules/nginx-development-kit/examples/http/set_var/ngx_http_set_var_examples_module.c rename to debian/modules/http-ndk/examples/http/set_var/ngx_http_set_var_examples_module.c diff --git a/debian/modules/nginx-development-kit/ngx_auto_lib_core b/debian/modules/http-ndk/ngx_auto_lib_core similarity index 100% rename from debian/modules/nginx-development-kit/ngx_auto_lib_core rename to debian/modules/http-ndk/ngx_auto_lib_core diff --git a/debian/modules/nginx-development-kit/notes/CHANGES b/debian/modules/http-ndk/notes/CHANGES similarity index 100% rename from debian/modules/nginx-development-kit/notes/CHANGES rename to debian/modules/http-ndk/notes/CHANGES diff --git a/debian/modules/nginx-development-kit/notes/LICENSE b/debian/modules/http-ndk/notes/LICENSE similarity index 100% rename from debian/modules/nginx-development-kit/notes/LICENSE rename to debian/modules/http-ndk/notes/LICENSE diff --git a/debian/modules/nginx-development-kit/objs/ndk_array.h b/debian/modules/http-ndk/objs/ndk_array.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_array.h rename to debian/modules/http-ndk/objs/ndk_array.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_conf_cmd_basic.h b/debian/modules/http-ndk/objs/ndk_conf_cmd_basic.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_conf_cmd_basic.h rename to debian/modules/http-ndk/objs/ndk_conf_cmd_basic.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_conf_cmd_extra.h b/debian/modules/http-ndk/objs/ndk_conf_cmd_extra.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_conf_cmd_extra.h rename to debian/modules/http-ndk/objs/ndk_conf_cmd_extra.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_conf_merge.h b/debian/modules/http-ndk/objs/ndk_conf_merge.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_conf_merge.h rename to debian/modules/http-ndk/objs/ndk_conf_merge.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_config.c b/debian/modules/http-ndk/objs/ndk_config.c similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_config.c rename to debian/modules/http-ndk/objs/ndk_config.c diff --git a/debian/modules/nginx-development-kit/objs/ndk_config.h b/debian/modules/http-ndk/objs/ndk_config.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_config.h rename to debian/modules/http-ndk/objs/ndk_config.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_includes.h b/debian/modules/http-ndk/objs/ndk_includes.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_includes.h rename to debian/modules/http-ndk/objs/ndk_includes.h diff --git a/debian/modules/nginx-development-kit/objs/ndk_palloc.h b/debian/modules/http-ndk/objs/ndk_palloc.h similarity index 100% rename from debian/modules/nginx-development-kit/objs/ndk_palloc.h rename to debian/modules/http-ndk/objs/ndk_palloc.h diff --git a/debian/modules/nginx-development-kit/patches/auto_config b/debian/modules/http-ndk/patches/auto_config similarity index 100% rename from debian/modules/nginx-development-kit/patches/auto_config rename to debian/modules/http-ndk/patches/auto_config diff --git a/debian/modules/nginx-development-kit/patches/expose_rewrite_functions b/debian/modules/http-ndk/patches/expose_rewrite_functions similarity index 100% rename from debian/modules/nginx-development-kit/patches/expose_rewrite_functions rename to debian/modules/http-ndk/patches/expose_rewrite_functions diff --git a/debian/modules/nginx-development-kit/patches/rewrite_phase_handler b/debian/modules/http-ndk/patches/rewrite_phase_handler similarity index 100% rename from debian/modules/nginx-development-kit/patches/rewrite_phase_handler rename to debian/modules/http-ndk/patches/rewrite_phase_handler diff --git a/debian/modules/nginx-development-kit/src/hash/md5.h b/debian/modules/http-ndk/src/hash/md5.h similarity index 100% rename from debian/modules/nginx-development-kit/src/hash/md5.h rename to debian/modules/http-ndk/src/hash/md5.h diff --git a/debian/modules/nginx-development-kit/src/hash/murmurhash2.c b/debian/modules/http-ndk/src/hash/murmurhash2.c similarity index 100% rename from debian/modules/nginx-development-kit/src/hash/murmurhash2.c rename to debian/modules/http-ndk/src/hash/murmurhash2.c diff --git a/debian/modules/nginx-development-kit/src/hash/sha.h b/debian/modules/http-ndk/src/hash/sha.h similarity index 100% rename from debian/modules/nginx-development-kit/src/hash/sha.h rename to debian/modules/http-ndk/src/hash/sha.h diff --git a/debian/modules/nginx-development-kit/src/ndk.c b/debian/modules/http-ndk/src/ndk.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk.c rename to debian/modules/http-ndk/src/ndk.c diff --git a/debian/modules/nginx-development-kit/src/ndk.h b/debian/modules/http-ndk/src/ndk.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk.h rename to debian/modules/http-ndk/src/ndk.h diff --git a/debian/modules/nginx-development-kit/src/ndk_buf.c b/debian/modules/http-ndk/src/ndk_buf.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_buf.c rename to debian/modules/http-ndk/src/ndk_buf.c diff --git a/debian/modules/nginx-development-kit/src/ndk_buf.h b/debian/modules/http-ndk/src/ndk_buf.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_buf.h rename to debian/modules/http-ndk/src/ndk_buf.h diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_path.c b/debian/modules/http-ndk/src/ndk_complex_path.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_path.c rename to debian/modules/http-ndk/src/ndk_complex_path.c diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_path.h b/debian/modules/http-ndk/src/ndk_complex_path.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_path.h rename to debian/modules/http-ndk/src/ndk_complex_path.h diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_value.c b/debian/modules/http-ndk/src/ndk_complex_value.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_value.c rename to debian/modules/http-ndk/src/ndk_complex_value.c diff --git a/debian/modules/nginx-development-kit/src/ndk_complex_value.h b/debian/modules/http-ndk/src/ndk_complex_value.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_complex_value.h rename to debian/modules/http-ndk/src/ndk_complex_value.h diff --git a/debian/modules/nginx-development-kit/src/ndk_conf_file.c b/debian/modules/http-ndk/src/ndk_conf_file.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_conf_file.c rename to debian/modules/http-ndk/src/ndk_conf_file.c diff --git a/debian/modules/nginx-development-kit/src/ndk_conf_file.h b/debian/modules/http-ndk/src/ndk_conf_file.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_conf_file.h rename to debian/modules/http-ndk/src/ndk_conf_file.h diff --git a/debian/modules/nginx-development-kit/src/ndk_debug.c b/debian/modules/http-ndk/src/ndk_debug.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_debug.c rename to debian/modules/http-ndk/src/ndk_debug.c diff --git a/debian/modules/nginx-development-kit/src/ndk_debug.h b/debian/modules/http-ndk/src/ndk_debug.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_debug.h rename to debian/modules/http-ndk/src/ndk_debug.h diff --git a/debian/modules/nginx-development-kit/src/ndk_encoding.c b/debian/modules/http-ndk/src/ndk_encoding.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_encoding.c rename to debian/modules/http-ndk/src/ndk_encoding.c diff --git a/debian/modules/nginx-development-kit/src/ndk_encoding.h b/debian/modules/http-ndk/src/ndk_encoding.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_encoding.h rename to debian/modules/http-ndk/src/ndk_encoding.h diff --git a/debian/modules/nginx-development-kit/src/ndk_hash.c b/debian/modules/http-ndk/src/ndk_hash.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_hash.c rename to debian/modules/http-ndk/src/ndk_hash.c diff --git a/debian/modules/nginx-development-kit/src/ndk_hash.h b/debian/modules/http-ndk/src/ndk_hash.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_hash.h rename to debian/modules/http-ndk/src/ndk_hash.h diff --git a/debian/modules/nginx-development-kit/src/ndk_http.c b/debian/modules/http-ndk/src/ndk_http.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_http.c rename to debian/modules/http-ndk/src/ndk_http.c diff --git a/debian/modules/nginx-development-kit/src/ndk_http.h b/debian/modules/http-ndk/src/ndk_http.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_http.h rename to debian/modules/http-ndk/src/ndk_http.h diff --git a/debian/modules/nginx-development-kit/src/ndk_http_headers.h b/debian/modules/http-ndk/src/ndk_http_headers.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_http_headers.h rename to debian/modules/http-ndk/src/ndk_http_headers.h diff --git a/debian/modules/nginx-development-kit/src/ndk_log.c b/debian/modules/http-ndk/src/ndk_log.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_log.c rename to debian/modules/http-ndk/src/ndk_log.c diff --git a/debian/modules/nginx-development-kit/src/ndk_log.h b/debian/modules/http-ndk/src/ndk_log.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_log.h rename to debian/modules/http-ndk/src/ndk_log.h diff --git a/debian/modules/nginx-development-kit/src/ndk_parse.h b/debian/modules/http-ndk/src/ndk_parse.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_parse.h rename to debian/modules/http-ndk/src/ndk_parse.h diff --git a/debian/modules/nginx-development-kit/src/ndk_path.c b/debian/modules/http-ndk/src/ndk_path.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_path.c rename to debian/modules/http-ndk/src/ndk_path.c diff --git a/debian/modules/nginx-development-kit/src/ndk_path.h b/debian/modules/http-ndk/src/ndk_path.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_path.h rename to debian/modules/http-ndk/src/ndk_path.h diff --git a/debian/modules/nginx-development-kit/src/ndk_process.c b/debian/modules/http-ndk/src/ndk_process.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_process.c rename to debian/modules/http-ndk/src/ndk_process.c diff --git a/debian/modules/nginx-development-kit/src/ndk_process.h b/debian/modules/http-ndk/src/ndk_process.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_process.h rename to debian/modules/http-ndk/src/ndk_process.h diff --git a/debian/modules/nginx-development-kit/src/ndk_regex.c b/debian/modules/http-ndk/src/ndk_regex.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_regex.c rename to debian/modules/http-ndk/src/ndk_regex.c diff --git a/debian/modules/nginx-development-kit/src/ndk_regex.h b/debian/modules/http-ndk/src/ndk_regex.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_regex.h rename to debian/modules/http-ndk/src/ndk_regex.h diff --git a/debian/modules/nginx-development-kit/src/ndk_rewrite.c b/debian/modules/http-ndk/src/ndk_rewrite.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_rewrite.c rename to debian/modules/http-ndk/src/ndk_rewrite.c diff --git a/debian/modules/nginx-development-kit/src/ndk_rewrite.h b/debian/modules/http-ndk/src/ndk_rewrite.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_rewrite.h rename to debian/modules/http-ndk/src/ndk_rewrite.h diff --git a/debian/modules/nginx-development-kit/src/ndk_set_var.c b/debian/modules/http-ndk/src/ndk_set_var.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_set_var.c rename to debian/modules/http-ndk/src/ndk_set_var.c diff --git a/debian/modules/nginx-development-kit/src/ndk_set_var.h b/debian/modules/http-ndk/src/ndk_set_var.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_set_var.h rename to debian/modules/http-ndk/src/ndk_set_var.h diff --git a/debian/modules/nginx-development-kit/src/ndk_string.c b/debian/modules/http-ndk/src/ndk_string.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_string.c rename to debian/modules/http-ndk/src/ndk_string.c diff --git a/debian/modules/nginx-development-kit/src/ndk_string.h b/debian/modules/http-ndk/src/ndk_string.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_string.h rename to debian/modules/http-ndk/src/ndk_string.h diff --git a/debian/modules/nginx-development-kit/src/ndk_string_util.h b/debian/modules/http-ndk/src/ndk_string_util.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_string_util.h rename to debian/modules/http-ndk/src/ndk_string_util.h diff --git a/debian/modules/nginx-development-kit/src/ndk_upstream_list.c b/debian/modules/http-ndk/src/ndk_upstream_list.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_upstream_list.c rename to debian/modules/http-ndk/src/ndk_upstream_list.c diff --git a/debian/modules/nginx-development-kit/src/ndk_upstream_list.h b/debian/modules/http-ndk/src/ndk_upstream_list.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_upstream_list.h rename to debian/modules/http-ndk/src/ndk_upstream_list.h diff --git a/debian/modules/nginx-development-kit/src/ndk_uri.c b/debian/modules/http-ndk/src/ndk_uri.c similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_uri.c rename to debian/modules/http-ndk/src/ndk_uri.c diff --git a/debian/modules/nginx-development-kit/src/ndk_uri.h b/debian/modules/http-ndk/src/ndk_uri.h similarity index 100% rename from debian/modules/nginx-development-kit/src/ndk_uri.h rename to debian/modules/http-ndk/src/ndk_uri.h diff --git a/debian/modules/ngx_http_substitutions_filter_module/CHANGES b/debian/modules/http-subs-filter/CHANGES similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/CHANGES rename to debian/modules/http-subs-filter/CHANGES diff --git a/debian/modules/ngx_http_substitutions_filter_module/README b/debian/modules/http-subs-filter/README similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/README rename to debian/modules/http-subs-filter/README diff --git a/debian/modules/ngx_http_substitutions_filter_module/config b/debian/modules/http-subs-filter/config similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/config rename to debian/modules/http-subs-filter/config diff --git a/debian/modules/ngx_http_substitutions_filter_module/doc/README.google_code_home_page.wiki b/debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/doc/README.google_code_home_page.wiki rename to debian/modules/http-subs-filter/doc/README.google_code_home_page.wiki diff --git a/debian/modules/ngx_http_substitutions_filter_module/doc/README.html b/debian/modules/http-subs-filter/doc/README.html similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/doc/README.html rename to debian/modules/http-subs-filter/doc/README.html diff --git a/debian/modules/ngx_http_substitutions_filter_module/doc/README.wiki b/debian/modules/http-subs-filter/doc/README.wiki similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/doc/README.wiki rename to debian/modules/http-subs-filter/doc/README.wiki diff --git a/debian/modules/ngx_http_substitutions_filter_module/ngx_http_subs_filter_module.c b/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/ngx_http_subs_filter_module.c rename to debian/modules/http-subs-filter/ngx_http_subs_filter_module.c diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/README b/debian/modules/http-subs-filter/test/README similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/README rename to debian/modules/http-subs-filter/test/README diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/AutoInstall.pm b/debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/AutoInstall.pm rename to debian/modules/http-subs-filter/test/inc/Module/AutoInstall.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install.pm b/debian/modules/http-subs-filter/test/inc/Module/Install.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/AutoInstall.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/AutoInstall.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/AutoInstall.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Base.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Base.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Base.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Can.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Can.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Can.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Fetch.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Fetch.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Fetch.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Include.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Include.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Include.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Makefile.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Makefile.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Makefile.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Metadata.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Metadata.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Metadata.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/TestBase.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/TestBase.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/TestBase.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Win32.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/Win32.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/Win32.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/WriteAll.pm b/debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Module/Install/WriteAll.pm rename to debian/modules/http-subs-filter/test/inc/Module/Install/WriteAll.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Spiffy.pm b/debian/modules/http-subs-filter/test/inc/Spiffy.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Spiffy.pm rename to debian/modules/http-subs-filter/test/inc/Spiffy.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base.pm b/debian/modules/http-subs-filter/test/inc/Test/Base.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base.pm rename to debian/modules/http-subs-filter/test/inc/Test/Base.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base/Filter.pm b/debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Base/Filter.pm rename to debian/modules/http-subs-filter/test/inc/Test/Base/Filter.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder.pm b/debian/modules/http-subs-filter/test/inc/Test/Builder.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder.pm rename to debian/modules/http-subs-filter/test/inc/Test/Builder.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder/Module.pm b/debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/Builder/Module.pm rename to debian/modules/http-subs-filter/test/inc/Test/Builder/Module.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/More.pm b/debian/modules/http-subs-filter/test/inc/Test/More.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/inc/Test/More.pm rename to debian/modules/http-subs-filter/test/inc/Test/More.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/LWP.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/LWP.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx/LWP.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Socket.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Socket.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx/Socket.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Util.pm b/debian/modules/http-subs-filter/test/lib/Test/Nginx/Util.pm similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/lib/Test/Nginx/Util.pm rename to debian/modules/http-subs-filter/test/lib/Test/Nginx/Util.pm diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs.t b/debian/modules/http-subs-filter/test/t/subs.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs.t rename to debian/modules/http-subs-filter/test/t/subs.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_capture.t b/debian/modules/http-subs-filter/test/t/subs_capture.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_capture.t rename to debian/modules/http-subs-filter/test/t/subs_capture.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_fix_string.t b/debian/modules/http-subs-filter/test/t/subs_fix_string.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_fix_string.t rename to debian/modules/http-subs-filter/test/t/subs_fix_string.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_regex.t b/debian/modules/http-subs-filter/test/t/subs_regex.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_regex.t rename to debian/modules/http-subs-filter/test/t/subs_regex.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/t/subs_types.t b/debian/modules/http-subs-filter/test/t/subs_types.t similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/t/subs_types.t rename to debian/modules/http-subs-filter/test/t/subs_types.t diff --git a/debian/modules/ngx_http_substitutions_filter_module/test/test.sh b/debian/modules/http-subs-filter/test/test.sh similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/test/test.sh rename to debian/modules/http-subs-filter/test/test.sh diff --git a/debian/modules/ngx_http_substitutions_filter_module/util/update-readme.sh b/debian/modules/http-subs-filter/util/update-readme.sh similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/util/update-readme.sh rename to debian/modules/http-subs-filter/util/update-readme.sh diff --git a/debian/modules/ngx_http_substitutions_filter_module/util/wiki2google_code_homepage.pl b/debian/modules/http-subs-filter/util/wiki2google_code_homepage.pl similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/util/wiki2google_code_homepage.pl rename to debian/modules/http-subs-filter/util/wiki2google_code_homepage.pl diff --git a/debian/modules/ngx_http_substitutions_filter_module/util/wiki2pod.pl b/debian/modules/http-subs-filter/util/wiki2pod.pl similarity index 100% rename from debian/modules/ngx_http_substitutions_filter_module/util/wiki2pod.pl rename to debian/modules/http-subs-filter/util/wiki2pod.pl diff --git a/debian/modules/nginx-upload-progress/CHANGES b/debian/modules/http-uploadprogress/CHANGES similarity index 100% rename from debian/modules/nginx-upload-progress/CHANGES rename to debian/modules/http-uploadprogress/CHANGES diff --git a/debian/modules/nginx-upload-progress/LICENSE b/debian/modules/http-uploadprogress/LICENSE similarity index 100% rename from debian/modules/nginx-upload-progress/LICENSE rename to debian/modules/http-uploadprogress/LICENSE diff --git a/debian/modules/nginx-upload-progress/Makefile b/debian/modules/http-uploadprogress/Makefile similarity index 100% rename from debian/modules/nginx-upload-progress/Makefile rename to debian/modules/http-uploadprogress/Makefile diff --git a/debian/modules/nginx-upload-progress/README b/debian/modules/http-uploadprogress/README similarity index 100% rename from debian/modules/nginx-upload-progress/README rename to debian/modules/http-uploadprogress/README diff --git a/debian/modules/nginx-upload-progress/config b/debian/modules/http-uploadprogress/config similarity index 100% rename from debian/modules/nginx-upload-progress/config rename to debian/modules/http-uploadprogress/config diff --git a/debian/modules/nginx-upload-progress/ngx_http_uploadprogress_module.c b/debian/modules/http-uploadprogress/ngx_http_uploadprogress_module.c similarity index 100% rename from debian/modules/nginx-upload-progress/ngx_http_uploadprogress_module.c rename to debian/modules/http-uploadprogress/ngx_http_uploadprogress_module.c diff --git a/debian/modules/nginx-upload-progress/test/client.sh b/debian/modules/http-uploadprogress/test/client.sh similarity index 100% rename from debian/modules/nginx-upload-progress/test/client.sh rename to debian/modules/http-uploadprogress/test/client.sh diff --git a/debian/modules/nginx-upload-progress/test/stress.sh b/debian/modules/http-uploadprogress/test/stress.sh similarity index 100% rename from debian/modules/nginx-upload-progress/test/stress.sh rename to debian/modules/http-uploadprogress/test/stress.sh diff --git a/debian/modules/nginx-upstream-fair/.gdbinit b/debian/modules/http-upstream-fair/.gdbinit similarity index 100% rename from debian/modules/nginx-upstream-fair/.gdbinit rename to debian/modules/http-upstream-fair/.gdbinit diff --git a/debian/modules/nginx-upstream-fair/README b/debian/modules/http-upstream-fair/README similarity index 100% rename from debian/modules/nginx-upstream-fair/README rename to debian/modules/http-upstream-fair/README diff --git a/debian/modules/nginx-upstream-fair/config b/debian/modules/http-upstream-fair/config similarity index 100% rename from debian/modules/nginx-upstream-fair/config rename to debian/modules/http-upstream-fair/config diff --git a/debian/modules/nginx-upstream-fair/ngx_http_upstream_fair_module.c b/debian/modules/http-upstream-fair/ngx_http_upstream_fair_module.c similarity index 100% rename from debian/modules/nginx-upstream-fair/ngx_http_upstream_fair_module.c rename to debian/modules/http-upstream-fair/ngx_http_upstream_fair_module.c diff --git a/debian/modules/patches/nginx-cache-purge/dynamic-module.patch b/debian/modules/patches/http-cache-purge/dynamic-module.patch similarity index 100% rename from debian/modules/patches/nginx-cache-purge/dynamic-module.patch rename to debian/modules/patches/http-cache-purge/dynamic-module.patch diff --git a/debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch b/debian/modules/patches/http-cache-purge/segfault-1.11.6.patch similarity index 100% rename from debian/modules/patches/nginx-cache-purge/segfault-1.11.6.patch rename to debian/modules/patches/http-cache-purge/segfault-1.11.6.patch diff --git a/debian/modules/patches/nginx-cache-purge/series b/debian/modules/patches/http-cache-purge/series similarity index 100% rename from debian/modules/patches/nginx-cache-purge/series rename to debian/modules/patches/http-cache-purge/series diff --git a/debian/modules/patches/nginx-dav-ext-module/dynamic-module.patch b/debian/modules/patches/http-dav-ext/dynamic-module.patch similarity index 100% rename from debian/modules/patches/nginx-dav-ext-module/dynamic-module.patch rename to debian/modules/patches/http-dav-ext/dynamic-module.patch diff --git a/debian/modules/patches/nginx-dav-ext-module/series b/debian/modules/patches/http-dav-ext/series similarity index 100% rename from debian/modules/patches/nginx-dav-ext-module/series rename to debian/modules/patches/http-dav-ext/series diff --git a/debian/modules/patches/nginx-echo/build-nginx-1.11.11.patch b/debian/modules/patches/http-echo/build-nginx-1.11.11.patch similarity index 100% rename from debian/modules/patches/nginx-echo/build-nginx-1.11.11.patch rename to debian/modules/patches/http-echo/build-nginx-1.11.11.patch diff --git a/debian/modules/patches/nginx-echo/series b/debian/modules/patches/http-echo/series similarity index 100% rename from debian/modules/patches/nginx-echo/series rename to debian/modules/patches/http-echo/series diff --git a/debian/modules/patches/nginx-lua/discover-luajit-2.1.patch b/debian/modules/patches/http-lua/discover-luajit-2.1.patch similarity index 100% rename from debian/modules/patches/nginx-lua/discover-luajit-2.1.patch rename to debian/modules/patches/http-lua/discover-luajit-2.1.patch diff --git a/debian/modules/patches/nginx-lua/openssl-1.1.0.patch b/debian/modules/patches/http-lua/openssl-1.1.0.patch similarity index 100% rename from debian/modules/patches/nginx-lua/openssl-1.1.0.patch rename to debian/modules/patches/http-lua/openssl-1.1.0.patch diff --git a/debian/modules/patches/nginx-lua/series b/debian/modules/patches/http-lua/series similarity index 100% rename from debian/modules/patches/nginx-lua/series rename to debian/modules/patches/http-lua/series diff --git a/debian/modules/patches/ngx_http_substitutions_filter_module/dynamic-module.patch b/debian/modules/patches/http-subs-filter/dynamic-module.patch similarity index 100% rename from debian/modules/patches/ngx_http_substitutions_filter_module/dynamic-module.patch rename to debian/modules/patches/http-subs-filter/dynamic-module.patch diff --git a/debian/modules/patches/ngx_http_substitutions_filter_module/series b/debian/modules/patches/http-subs-filter/series similarity index 100% rename from debian/modules/patches/ngx_http_substitutions_filter_module/series rename to debian/modules/patches/http-subs-filter/series diff --git a/debian/modules/patches/nginx-upstream-fair/drop-default-port.patch b/debian/modules/patches/http-upstream-fair/drop-default-port.patch similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/drop-default-port.patch rename to debian/modules/patches/http-upstream-fair/drop-default-port.patch diff --git a/debian/modules/patches/nginx-upstream-fair/dynamic-module.patch b/debian/modules/patches/http-upstream-fair/dynamic-module.patch similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/dynamic-module.patch rename to debian/modules/patches/http-upstream-fair/dynamic-module.patch diff --git a/debian/modules/patches/nginx-upstream-fair/openssl-1.1.0.patch b/debian/modules/patches/http-upstream-fair/openssl-1.1.0.patch similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/openssl-1.1.0.patch rename to debian/modules/patches/http-upstream-fair/openssl-1.1.0.patch diff --git a/debian/modules/patches/nginx-upstream-fair/series b/debian/modules/patches/http-upstream-fair/series similarity index 100% rename from debian/modules/patches/nginx-upstream-fair/series rename to debian/modules/patches/http-upstream-fair/series diff --git a/debian/modules/nginx-rtmp/AUTHORS b/debian/modules/rtmp/AUTHORS similarity index 100% rename from debian/modules/nginx-rtmp/AUTHORS rename to debian/modules/rtmp/AUTHORS diff --git a/debian/modules/nginx-rtmp/LICENSE b/debian/modules/rtmp/LICENSE similarity index 100% rename from debian/modules/nginx-rtmp/LICENSE rename to debian/modules/rtmp/LICENSE diff --git a/debian/modules/nginx-rtmp/README.md b/debian/modules/rtmp/README.md similarity index 100% rename from debian/modules/nginx-rtmp/README.md rename to debian/modules/rtmp/README.md diff --git a/debian/modules/nginx-rtmp/config b/debian/modules/rtmp/config similarity index 100% rename from debian/modules/nginx-rtmp/config rename to debian/modules/rtmp/config diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c b/debian/modules/rtmp/dash/ngx_rtmp_dash_module.c similarity index 100% rename from debian/modules/nginx-rtmp/dash/ngx_rtmp_dash_module.c rename to debian/modules/rtmp/dash/ngx_rtmp_dash_module.c diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c b/debian/modules/rtmp/dash/ngx_rtmp_mp4.c similarity index 100% rename from debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.c rename to debian/modules/rtmp/dash/ngx_rtmp_mp4.c diff --git a/debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h b/debian/modules/rtmp/dash/ngx_rtmp_mp4.h similarity index 100% rename from debian/modules/nginx-rtmp/dash/ngx_rtmp_mp4.h rename to debian/modules/rtmp/dash/ngx_rtmp_mp4.h diff --git a/debian/modules/nginx-rtmp/doc/README.md b/debian/modules/rtmp/doc/README.md similarity index 100% rename from debian/modules/nginx-rtmp/doc/README.md rename to debian/modules/rtmp/doc/README.md diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c b/debian/modules/rtmp/hls/ngx_rtmp_hls_module.c similarity index 100% rename from debian/modules/nginx-rtmp/hls/ngx_rtmp_hls_module.c rename to debian/modules/rtmp/hls/ngx_rtmp_hls_module.c diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c b/debian/modules/rtmp/hls/ngx_rtmp_mpegts.c similarity index 100% rename from debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.c rename to debian/modules/rtmp/hls/ngx_rtmp_mpegts.c diff --git a/debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h b/debian/modules/rtmp/hls/ngx_rtmp_mpegts.h similarity index 100% rename from debian/modules/nginx-rtmp/hls/ngx_rtmp_mpegts.h rename to debian/modules/rtmp/hls/ngx_rtmp_mpegts.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp.c b/debian/modules/rtmp/ngx_rtmp.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp.c rename to debian/modules/rtmp/ngx_rtmp.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp.h b/debian/modules/rtmp/ngx_rtmp.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp.h rename to debian/modules/rtmp/ngx_rtmp.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_access_module.c b/debian/modules/rtmp/ngx_rtmp_access_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_access_module.c rename to debian/modules/rtmp/ngx_rtmp_access_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_amf.c b/debian/modules/rtmp/ngx_rtmp_amf.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_amf.c rename to debian/modules/rtmp/ngx_rtmp_amf.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_amf.h b/debian/modules/rtmp/ngx_rtmp_amf.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_amf.h rename to debian/modules/rtmp/ngx_rtmp_amf.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c b/debian/modules/rtmp/ngx_rtmp_auto_push_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_auto_push_module.c rename to debian/modules/rtmp/ngx_rtmp_auto_push_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c b/debian/modules/rtmp/ngx_rtmp_bandwidth.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.c rename to debian/modules/rtmp/ngx_rtmp_bandwidth.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h b/debian/modules/rtmp/ngx_rtmp_bandwidth.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bandwidth.h rename to debian/modules/rtmp/ngx_rtmp_bandwidth.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bitop.c b/debian/modules/rtmp/ngx_rtmp_bitop.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bitop.c rename to debian/modules/rtmp/ngx_rtmp_bitop.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_bitop.h b/debian/modules/rtmp/ngx_rtmp_bitop.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_bitop.h rename to debian/modules/rtmp/ngx_rtmp_bitop.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c b/debian/modules/rtmp/ngx_rtmp_cmd_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.c rename to debian/modules/rtmp/ngx_rtmp_cmd_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h b/debian/modules/rtmp/ngx_rtmp_cmd_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_cmd_module.h rename to debian/modules/rtmp/ngx_rtmp_cmd_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c b/debian/modules/rtmp/ngx_rtmp_codec_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_codec_module.c rename to debian/modules/rtmp/ngx_rtmp_codec_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h b/debian/modules/rtmp/ngx_rtmp_codec_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_codec_module.h rename to debian/modules/rtmp/ngx_rtmp_codec_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_control_module.c b/debian/modules/rtmp/ngx_rtmp_control_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_control_module.c rename to debian/modules/rtmp/ngx_rtmp_control_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_core_module.c b/debian/modules/rtmp/ngx_rtmp_core_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_core_module.c rename to debian/modules/rtmp/ngx_rtmp_core_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_eval.c b/debian/modules/rtmp/ngx_rtmp_eval.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_eval.c rename to debian/modules/rtmp/ngx_rtmp_eval.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_eval.h b/debian/modules/rtmp/ngx_rtmp_eval.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_eval.h rename to debian/modules/rtmp/ngx_rtmp_eval.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c b/debian/modules/rtmp/ngx_rtmp_exec_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_exec_module.c rename to debian/modules/rtmp/ngx_rtmp_exec_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c b/debian/modules/rtmp/ngx_rtmp_flv_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_flv_module.c rename to debian/modules/rtmp/ngx_rtmp_flv_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_handler.c b/debian/modules/rtmp/ngx_rtmp_handler.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_handler.c rename to debian/modules/rtmp/ngx_rtmp_handler.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_handshake.c b/debian/modules/rtmp/ngx_rtmp_handshake.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_handshake.c rename to debian/modules/rtmp/ngx_rtmp_handshake.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_init.c b/debian/modules/rtmp/ngx_rtmp_init.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_init.c rename to debian/modules/rtmp/ngx_rtmp_init.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c b/debian/modules/rtmp/ngx_rtmp_limit_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_limit_module.c rename to debian/modules/rtmp/ngx_rtmp_limit_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_live_module.c b/debian/modules/rtmp/ngx_rtmp_live_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_live_module.c rename to debian/modules/rtmp/ngx_rtmp_live_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_live_module.h b/debian/modules/rtmp/ngx_rtmp_live_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_live_module.h rename to debian/modules/rtmp/ngx_rtmp_live_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_log_module.c b/debian/modules/rtmp/ngx_rtmp_log_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_log_module.c rename to debian/modules/rtmp/ngx_rtmp_log_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c b/debian/modules/rtmp/ngx_rtmp_mp4_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_mp4_module.c rename to debian/modules/rtmp/ngx_rtmp_mp4_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c b/debian/modules/rtmp/ngx_rtmp_netcall_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.c rename to debian/modules/rtmp/ngx_rtmp_netcall_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h b/debian/modules/rtmp/ngx_rtmp_netcall_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_netcall_module.h rename to debian/modules/rtmp/ngx_rtmp_netcall_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c b/debian/modules/rtmp/ngx_rtmp_notify_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_notify_module.c rename to debian/modules/rtmp/ngx_rtmp_notify_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_play_module.c b/debian/modules/rtmp/ngx_rtmp_play_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_play_module.c rename to debian/modules/rtmp/ngx_rtmp_play_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_play_module.h b/debian/modules/rtmp/ngx_rtmp_play_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_play_module.h rename to debian/modules/rtmp/ngx_rtmp_play_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c b/debian/modules/rtmp/ngx_rtmp_proxy_protocol.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.c rename to debian/modules/rtmp/ngx_rtmp_proxy_protocol.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h b/debian/modules/rtmp/ngx_rtmp_proxy_protocol.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_proxy_protocol.h rename to debian/modules/rtmp/ngx_rtmp_proxy_protocol.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_receive.c b/debian/modules/rtmp/ngx_rtmp_receive.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_receive.c rename to debian/modules/rtmp/ngx_rtmp_receive.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_record_module.c b/debian/modules/rtmp/ngx_rtmp_record_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_record_module.c rename to debian/modules/rtmp/ngx_rtmp_record_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_record_module.h b/debian/modules/rtmp/ngx_rtmp_record_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_record_module.h rename to debian/modules/rtmp/ngx_rtmp_record_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c b/debian/modules/rtmp/ngx_rtmp_relay_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_relay_module.c rename to debian/modules/rtmp/ngx_rtmp_relay_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h b/debian/modules/rtmp/ngx_rtmp_relay_module.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_relay_module.h rename to debian/modules/rtmp/ngx_rtmp_relay_module.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_send.c b/debian/modules/rtmp/ngx_rtmp_send.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_send.c rename to debian/modules/rtmp/ngx_rtmp_send.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_shared.c b/debian/modules/rtmp/ngx_rtmp_shared.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_shared.c rename to debian/modules/rtmp/ngx_rtmp_shared.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c b/debian/modules/rtmp/ngx_rtmp_stat_module.c similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_stat_module.c rename to debian/modules/rtmp/ngx_rtmp_stat_module.c diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_streams.h b/debian/modules/rtmp/ngx_rtmp_streams.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_streams.h rename to debian/modules/rtmp/ngx_rtmp_streams.h diff --git a/debian/modules/nginx-rtmp/ngx_rtmp_version.h b/debian/modules/rtmp/ngx_rtmp_version.h similarity index 100% rename from debian/modules/nginx-rtmp/ngx_rtmp_version.h rename to debian/modules/rtmp/ngx_rtmp_version.h diff --git a/debian/modules/nginx-rtmp/stat.xsl b/debian/modules/rtmp/stat.xsl similarity index 100% rename from debian/modules/nginx-rtmp/stat.xsl rename to debian/modules/rtmp/stat.xsl diff --git a/debian/rules b/debian/rules index a852d02..981a57e 100755 --- a/debian/rules +++ b/debian/rules @@ -82,7 +82,7 @@ light_configure_flags := \ --without-http_referer_module \ --without-http_split_clients_module \ --without-http_userid_module \ - --add-dynamic-module=$(MODULESDIR)/nginx-echo + --add-dynamic-module=$(MODULESDIR)/http-echo full_configure_flags := \ $(common_configure_flags) \ @@ -98,11 +98,11 @@ full_configure_flags := \ --with-stream_ssl_preread_module \ --with-mail=dynamic \ --with-mail_ssl_module \ - --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ - --add-dynamic-module=$(MODULESDIR)/nginx-dav-ext-module \ - --add-dynamic-module=$(MODULESDIR)/nginx-echo \ - --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ - --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module + --add-dynamic-module=$(MODULESDIR)/http-auth-pam \ + --add-dynamic-module=$(MODULESDIR)/http-dav-ext \ + --add-dynamic-module=$(MODULESDIR)/http-echo \ + --add-dynamic-module=$(MODULESDIR)/http-upstream-fair \ + --add-dynamic-module=$(MODULESDIR)/http-subs-filter extras_configure_flags := \ $(common_configure_flags) \ @@ -123,19 +123,19 @@ extras_configure_flags := \ --with-stream=dynamic \ --with-stream_ssl_module \ --with-stream_ssl_preread_module \ - --add-dynamic-module=$(MODULESDIR)/headers-more-nginx-module \ - --add-dynamic-module=$(MODULESDIR)/nginx-auth-pam \ - --add-dynamic-module=$(MODULESDIR)/nginx-cache-purge \ - --add-dynamic-module=$(MODULESDIR)/nginx-dav-ext-module \ - --add-dynamic-module=$(MODULESDIR)/nginx-development-kit \ - --add-dynamic-module=$(MODULESDIR)/nginx-echo \ - --add-dynamic-module=$(MODULESDIR)/ngx-fancyindex \ + --add-dynamic-module=$(MODULESDIR)/http-headers-more-filter \ + --add-dynamic-module=$(MODULESDIR)/http-auth-pam \ + --add-dynamic-module=$(MODULESDIR)/http-cache-purge \ + --add-dynamic-module=$(MODULESDIR)/http-dav-ext \ + --add-dynamic-module=$(MODULESDIR)/http-ndk \ + --add-dynamic-module=$(MODULESDIR)/http-echo \ + --add-dynamic-module=$(MODULESDIR)/http-fancyindex \ --add-dynamic-module=$(MODULESDIR)/nchan \ - --add-dynamic-module=$(MODULESDIR)/nginx-lua \ - --add-dynamic-module=$(MODULESDIR)/nginx-rtmp \ - --add-dynamic-module=$(MODULESDIR)/nginx-upload-progress \ - --add-dynamic-module=$(MODULESDIR)/nginx-upstream-fair \ - --add-dynamic-module=$(MODULESDIR)/ngx_http_substitutions_filter_module + --add-dynamic-module=$(MODULESDIR)/http-lua \ + --add-dynamic-module=$(MODULESDIR)/rtmp \ + --add-dynamic-module=$(MODULESDIR)/http-uploadprogress \ + --add-dynamic-module=$(MODULESDIR)/http-upstream-fair \ + --add-dynamic-module=$(MODULESDIR)/http-subs-filter %: dh $@ --without autoreconf From 0305fe8ea3e438b80a815f2ef18e6ecc77cca6b7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 12 Oct 2017 10:37:08 +0300 Subject: [PATCH 035/414] Bump Standards-Version, no changes needed --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index e7a598a..17cfaab 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper (>= 10), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.1.0 +Standards-Version: 4.1.1 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git From bf0c6fce6e6887b65e129f7974c3e8df69c8c627 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 12 Oct 2017 10:35:21 +0300 Subject: [PATCH 036/414] Drop dh-systemd dependency since we depend on debhelper >= 10 Fixes build-depends-on-obsolete-package in lintian. --- debian/control | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/control b/debian/control index 17cfaab..b8ae948 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,6 @@ Uploaders: Kartik Mistry , Christos Trochalakis Build-Depends: debhelper (>= 10), po-debconf, - dh-systemd (>= 1.5), dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, From f056335a382b9ef80a0e7ea390c547ddeb61061e Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 12 Oct 2017 10:44:13 +0300 Subject: [PATCH 037/414] Release 1.13.6-1 --- debian/changelog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/debian/changelog b/debian/changelog index 396226e..8aa3e0a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +nginx (1.13.6-1) unstable; urgency=medium + + * New upstream version + * Normalize module paths in packaging repository + * Bump Standards-Version, no changes needed + * Drop dh-systemd dependency since we depend on debhelper >= 10 + + -- Christos Trochalakis Thu, 12 Oct 2017 10:37:29 +0300 + nginx (1.13.5-1) unstable; urgency=medium * New upstream version 1.13.5 From 10af9c3beff85db4b194106586a899169e734be8 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 13 Oct 2017 12:40:11 +0300 Subject: [PATCH 038/414] rtmp: Ship docs & examples Closes: #878368 --- debian/libnginx-mod-rtmp.docs | 2 +- debian/libnginx-mod-rtmp.examples | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/libnginx-mod-rtmp.docs b/debian/libnginx-mod-rtmp.docs index 8bb7d17..e5c5c00 100644 --- a/debian/libnginx-mod-rtmp.docs +++ b/debian/libnginx-mod-rtmp.docs @@ -1 +1 @@ -debian/modules/nginx-rtmp/README.md +debian/modules/rtmp/README.md diff --git a/debian/libnginx-mod-rtmp.examples b/debian/libnginx-mod-rtmp.examples index 6748d60..563f038 100644 --- a/debian/libnginx-mod-rtmp.examples +++ b/debian/libnginx-mod-rtmp.examples @@ -1 +1 @@ -debian/modules/nginx-rtmp/stat.xsl +debian/modules/rtmp/stat.xsl From 08248c9d96a3a6d83444f268219a8f8812c79f48 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Fri, 13 Oct 2017 12:59:41 +0300 Subject: [PATCH 039/414] Release 1.13.6-2 --- debian/changelog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/debian/changelog b/debian/changelog index 8aa3e0a..5be779e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.13.6-2) unstable; urgency=medium + + * rtmp: Ship docs & examples (Closes: #878368) + + -- Christos Trochalakis Fri, 13 Oct 2017 12:59:28 +0300 + nginx (1.13.6-1) unstable; urgency=medium * New upstream version From dfa79bec5c13485c7be06718a713fe2793568160 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 22 Nov 2017 16:31:37 +0200 Subject: [PATCH 040/414] New upstream version 1.13.7 --- CHANGES | 24 ++++++++++++ CHANGES.ru | 24 ++++++++++++ src/core/nginx.h | 4 +- src/core/ngx_conf_file.h | 2 +- src/core/ngx_cycle.c | 24 ++++++++---- src/event/ngx_event_openssl.h | 1 + src/http/modules/ngx_http_fastcgi_module.c | 1 + .../modules/ngx_http_gzip_filter_module.c | 38 ++++++++++++++++--- src/http/modules/ngx_http_ssi_filter_module.c | 15 ++++---- .../modules/ngx_http_xslt_filter_module.c | 15 +++++++- src/http/ngx_http_postpone_filter_module.c | 9 ++++- src/http/ngx_http_request.c | 7 ++++ src/http/ngx_http_upstream.c | 12 ++++++ src/mail/ngx_mail_proxy_module.c | 7 +++- src/stream/ngx_stream_proxy_module.c | 6 +++ 15 files changed, 160 insertions(+), 29 deletions(-) diff --git a/CHANGES b/CHANGES index 6a9fdcc..d93a938 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,28 @@ +Changes with nginx 1.13.7 21 Nov 2017 + + *) Bugfix: in the $upstream_status variable. + + *) Bugfix: a segmentation fault might occur in a worker process if a + backend returned a "101 Switching Protocols" response to a + subrequest. + + *) Bugfix: a segmentation fault occurred in a master process if a shared + memory zone size was changed during a reconfiguration and the + reconfiguration failed. + + *) Bugfix: in the ngx_http_fastcgi_module. + + *) Bugfix: nginx returned the 500 error if parameters without variables + were specified in the "xslt_stylesheet" directive. + + *) Workaround: "gzip filter failed to use preallocated memory" alerts + appeared in logs when using a zlib library variant from Intel. + + *) Bugfix: the "worker_shutdown_timeout" directive did not work when + using mail proxy and when proxying WebSocket connections. + + Changes with nginx 1.13.6 10 Oct 2017 *) Bugfix: switching to the next upstream server in the stream module diff --git a/CHANGES.ru b/CHANGES.ru index 6ea87c9..e688a5c 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,28 @@ +Изменения в nginx 1.13.7 21.11.2017 + + *) Исправление: в переменной $upstream_status. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если бэкенд возвращал ответ "101 Switching Protocols" на подзапрос. + + *) Исправление: если при переконфигурации изменялся размер зоны + разделяемой памяти и переконфигурация завершалась неудачно, то в + главном процессе происходил segmentation fault. + + *) Исправление: в модуле ngx_http_fastcgi_module. + + *) Исправление: nginx возвращал ошибку 500, если в директиве + xslt_stylesheet были заданы параметры без использования переменных. + + *) Изменение: при использовании варианта библиотеки zlib от Intel в лог + писались сообщения "gzip filter failed to use preallocated memory". + + *) Исправление: директива worker_shutdown_timeout не работала при + использовании почтового прокси-сервера и при проксировании + WebSocket-соединений. + + Изменения в nginx 1.13.6 10.10.2017 *) Исправление: при использовании директивы ssl_preread в модуле stream diff --git a/src/core/nginx.h b/src/core/nginx.h index 5806837..02b51ab 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013006 -#define NGINX_VERSION "1.13.6" +#define nginx_version 1013007 +#define NGINX_VERSION "1.13.7" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h index 213611f..9cd5806 100644 --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -128,7 +128,7 @@ struct ngx_conf_s { ngx_uint_t cmd_type; ngx_conf_handler_pt handler; - char *handler_conf; + void *handler_conf; }; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index 675a506..f3ac24d 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -470,8 +470,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) goto shm_zone_found; } - ngx_shm_free(&oshm_zone[n].shm); - break; } @@ -662,14 +660,26 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) n = 0; } - if (oshm_zone[i].shm.name.len == shm_zone[n].shm.name.len - && ngx_strncmp(oshm_zone[i].shm.name.data, - shm_zone[n].shm.name.data, - oshm_zone[i].shm.name.len) - == 0) + if (oshm_zone[i].shm.name.len != shm_zone[n].shm.name.len) { + continue; + } + + if (ngx_strncmp(oshm_zone[i].shm.name.data, + shm_zone[n].shm.name.data, + oshm_zone[i].shm.name.len) + != 0) + { + continue; + } + + if (oshm_zone[i].tag == shm_zone[n].tag + && oshm_zone[i].shm.size == shm_zone[n].shm.size + && !oshm_zone[i].noreuse) { goto live_shm_zone; } + + break; } ngx_shm_free(&oshm_zone[i].shm); diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index b9a3a96..623d851 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -22,6 +22,7 @@ #include #endif #include +#include #ifndef OPENSSL_NO_OCSP #include #endif diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index ea16eca..b4bb1d0 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2646,6 +2646,7 @@ ngx_http_fastcgi_process_record(ngx_http_request_t *r, } } + f->pos = p; f->state = state; return NGX_AGAIN; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index 73b6d89..e4c343c 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 gzheader:1; unsigned buffering:1; + unsigned intel:1; size_t zin; size_t zout; @@ -233,6 +234,8 @@ static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); 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_uint_t ngx_http_gzip_assume_intel; + static ngx_int_t ngx_http_gzip_header_filter(ngx_http_request_t *r) @@ -527,7 +530,27 @@ ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) * *) 5920 bytes on amd64 and sparc64 */ - ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); + if (!ngx_http_gzip_assume_intel) { + ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); + + } else { + /* + * A zlib variant from Intel, https://github.com/jtkukunas/zlib. + * It can force window bits to 13 for fast compression level, + * on processors with SSE 4.2 it uses 64K hash instead of scaling + * it from the specified memory level, and also introduces + * 16-byte padding in one out of the two window-sized buffers. + */ + + if (conf->level == 1) { + wbits = ngx_max(wbits, 13); + } + + ctx->allocated = 8192 + 16 + (1 << (wbits + 2)) + + (1 << (ngx_max(memlevel, 8) + 8)) + + (1 << (memlevel + 8)); + ctx->intel = 1; + } } @@ -1003,7 +1026,7 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) alloc = items * size; - if (alloc % 512 != 0 && alloc < 8192) { + if (items == 1 && alloc % 512 != 0 && alloc < 8192) { /* * The zlib deflate_state allocation, it takes about 6K, @@ -1025,9 +1048,14 @@ ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) return p; } - ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, - "gzip filter failed to use preallocated memory: %ud of %ui", - items * size, ctx->allocated); + if (ctx->intel) { + ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, + "gzip filter failed to use preallocated memory: " + "%ud of %ui", items * size, ctx->allocated); + + } else { + ngx_http_gzip_assume_intel = 1; + } p = ngx_palloc(ctx->request->pool, items * size); diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index e29e173..c799b2f 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -1630,8 +1630,7 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, u_char ch, *p, **value, *data, *part_data; size_t *size, len, prefix, part_len; ngx_str_t var, *val; - ngx_int_t key; - ngx_uint_t i, n, bracket, quoted; + ngx_uint_t i, n, bracket, quoted, key; ngx_array_t lengths, values; ngx_http_variable_value_t *vv; @@ -1883,9 +1882,8 @@ ngx_http_ssi_regex_match(ngx_http_request_t *r, ngx_str_t *pattern, int rc, *captures; u_char *p, errstr[NGX_MAX_CONF_ERRSTR]; size_t size; - ngx_int_t key; ngx_str_t *vv, name, value; - ngx_uint_t i, n; + ngx_uint_t i, n, key; ngx_http_ssi_ctx_t *ctx; ngx_http_ssi_var_t *var; ngx_regex_compile_t rgc; @@ -1988,10 +1986,10 @@ static ngx_int_t ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - ngx_int_t rc, key; + ngx_int_t rc; ngx_str_t *uri, *file, *wait, *set, *stub, args; ngx_buf_t *b; - ngx_uint_t flags, i; + ngx_uint_t flags, i, key; ngx_chain_t *cl, *tl, **ll, *out; ngx_http_request_t *sr; ngx_http_ssi_var_t *var; @@ -2248,9 +2246,9 @@ ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, { u_char *p; uintptr_t len; - ngx_int_t key; ngx_buf_t *b; ngx_str_t *var, *value, *enc, text; + ngx_uint_t key; ngx_chain_t *cl; ngx_http_variable_value_t *vv; @@ -2410,8 +2408,9 @@ static ngx_int_t ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - ngx_int_t key, rc; + ngx_int_t rc; ngx_str_t *name, *value, *vv; + ngx_uint_t key; ngx_http_ssi_var_t *var; ngx_http_ssi_ctx_t *mctx; diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index fae5895..ea7ce2a 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -686,8 +686,19 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, * specified in xslt_stylesheet directives */ - p = string.data; - last = string.data + string.len; + if (param[i].value.lengths) { + p = string.data; + + } else { + p = ngx_pnalloc(r->pool, string.len + 1); + if (p == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(p, string.data, string.len + 1); + } + + last = p + string.len; while (p && *p) { diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c index e893b83..55f2698 100644 --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -63,7 +63,10 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) if (r != c->data) { if (in) { - ngx_http_postpone_filter_add(r, in); + if (ngx_http_postpone_filter_add(r, in) != NGX_OK) { + return NGX_ERROR; + } + return NGX_OK; } @@ -86,7 +89,9 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (in) { - ngx_http_postpone_filter_add(r, in); + if (ngx_http_postpone_filter_add(r, in) != NGX_OK) { + return NGX_ERROR; + } } do { diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index de1b202..5668bf4 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -2225,6 +2225,13 @@ ngx_http_request_handler(ngx_event_t *ev) ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http run request: \"%V?%V\"", &r->uri, &r->args); + if (c->close) { + r->main->count++; + ngx_http_terminate_request(r, 0); + ngx_http_run_posted_requests(c); + return; + } + if (ev->delayed && ev->timedout) { ev->delayed = 0; ev->timedout = 0; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 2ea521b..75f463b 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -3206,6 +3206,13 @@ ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) /* TODO: prevent upgrade if not requested or not possible */ + if (r != r->main) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "connection upgrade in subrequest"); + ngx_http_upstream_finalize_request(r, u, NGX_ERROR); + return; + } + r->keepalive = 0; c->log->action = "proxying upgraded connection"; @@ -4111,6 +4118,7 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, switch (ft_type) { case NGX_HTTP_UPSTREAM_FT_TIMEOUT: + case NGX_HTTP_UPSTREAM_FT_HTTP_504: status = NGX_HTTP_GATEWAY_TIME_OUT; break; @@ -4118,6 +4126,10 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, status = NGX_HTTP_INTERNAL_SERVER_ERROR; break; + case NGX_HTTP_UPSTREAM_FT_HTTP_503: + status = NGX_HTTP_SERVICE_UNAVAILABLE; + break; + case NGX_HTTP_UPSTREAM_FT_HTTP_403: status = NGX_HTTP_FORBIDDEN; break; diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 007284b..1c86e54 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -882,10 +882,13 @@ ngx_mail_proxy_handler(ngx_event_t *ev) c = ev->data; s = c->data; - if (ev->timedout) { + if (ev->timedout || c->close) { c->log->action = "proxying"; - if (c == s->connection) { + if (c->close) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "shutdown timeout"); + + } else if (c == s->connection) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); c->timedout = 1; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 9d4b075..ad81cc8 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1290,6 +1290,12 @@ ngx_stream_proxy_process_connection(ngx_event_t *ev, ngx_uint_t from_upstream) s = c->data; u = s->upstream; + if (c->close) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, "shutdown timeout"); + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + return; + } + c = s->connection; pc = u->peer.connection; From 9f10b314887ff633e1ef28419538980904938425 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 10:51:58 +0200 Subject: [PATCH 041/414] Bump Standards-Version, no changes needed --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index b8ae948..38cd027 100644 --- a/debian/control +++ b/debian/control @@ -23,7 +23,7 @@ Build-Depends: debhelper (>= 10), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.1.1 +Standards-Version: 4.1.2 Homepage: http://nginx.net Vcs-Git: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git Vcs-Browser: https://anonscm.debian.org/cgit/pkg-nginx/nginx.git From 08d6a8fe7a78a1d008a1e566d7bd96b317c51a93 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Thu, 14 Dec 2017 10:53:44 +0200 Subject: [PATCH 042/414] debian/watch: switch to HTTPS for the upstream check Fixes lintian `source: debian-watch-uses-insecure-uri` info. --- debian/watch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/watch b/debian/watch index 6fa2f3e..0a39b11 100644 --- a/debian/watch +++ b/debian/watch @@ -1,3 +1,3 @@ version=3 opts=pgpsigurlmangle=s/$/.asc/ \ -http://nginx.org/download/nginx-(1\.13\.\d+)\.tar\.gz +https://nginx.org/download/nginx-(1\.13\.\d+)\.tar\.gz From 794cca0ebffcebe24c4d52eac33a961da1b79acd Mon Sep 17 00:00:00 2001 From: Mpampis Kostas Date: Sat, 22 Jul 2017 16:26:21 +0300 Subject: [PATCH 043/414] Automate modules watch & upgrade process This patch introduces the debian/ngxmod script and some helper files which can be used to automate the modules watch & upgrade process. The only subcommand for now is `uscan` and can be called as: $ debian/ngxmod uscan The uscan subcommand runs uscan for each nginx module listed in the newly deb822 formatted debian/modules/control using the watchfiles in debian/modules/watch. If a new version is available, it will ask you if you want to upgrade. If you agree, it will download the tarball, place it in the nginx source's parent directory and upgrade the module's source. After the upgrade, it will remove the files listed in the Files-Excluded module field and finally it will commit the changes. Closes: #869499 --- debian/modules/README.Modules-versions | 69 -------- debian/modules/control | 71 ++++++++ debian/modules/uupdate | 10 ++ debian/modules/watch/http-auth-pam | 4 + debian/modules/watch/http-cache-purge | 4 + debian/modules/watch/http-dav-ext | 4 + debian/modules/watch/http-echo | 4 + debian/modules/watch/http-fancyindex | 4 + debian/modules/watch/http-headers-more-filter | 4 + debian/modules/watch/http-lua | 4 + debian/modules/watch/http-ndk | 4 + debian/modules/watch/http-subs-filter | 4 + debian/modules/watch/http-uploadprogress | 4 + debian/modules/watch/nchan | 4 + debian/modules/watch/rtmp | 4 + debian/ngxmod | 156 ++++++++++++++++++ 16 files changed, 285 insertions(+), 69 deletions(-) delete mode 100644 debian/modules/README.Modules-versions create mode 100644 debian/modules/control create mode 100755 debian/modules/uupdate create mode 100644 debian/modules/watch/http-auth-pam create mode 100644 debian/modules/watch/http-cache-purge create mode 100644 debian/modules/watch/http-dav-ext create mode 100644 debian/modules/watch/http-echo create mode 100644 debian/modules/watch/http-fancyindex create mode 100644 debian/modules/watch/http-headers-more-filter create mode 100644 debian/modules/watch/http-lua create mode 100644 debian/modules/watch/http-ndk create mode 100644 debian/modules/watch/http-subs-filter create mode 100644 debian/modules/watch/http-uploadprogress create mode 100644 debian/modules/watch/nchan create mode 100644 debian/modules/watch/rtmp create mode 100755 debian/ngxmod diff --git a/debian/modules/README.Modules-versions b/debian/modules/README.Modules-versions deleted file mode 100644 index ff5f63b..0000000 --- a/debian/modules/README.Modules-versions +++ /dev/null @@ -1,69 +0,0 @@ -README for Modules versions ---------------------------- - - This file lists third party modules built with nginx in Debian, homepage and - version. - - headers-more-nginx-module - Homepage: https://github.com/agentzh/headers-more-nginx-module - Version: v0.32 - - nginx-development-kit - Homepage: https://github.com/simpl/ngx_devel_kit/ - Version: v0.3.0 - - nginx-auth-pam - Homepage: https://github.com/stogh/ngx_http_auth_pam_module - Version: 1.5.1 - - nginx-echo - Homepage: https://github.com/agentzh/echo-nginx-module - Version: v0.60 - Patch: build-nginx-1.11.11.patch - - nginx-lua - Homepage: https://github.com/openresty/lua-nginx-module - Version: v0.10.10 - Patch: openssl-1.1.0.patch - Patch: discover-luajit-2.1.patch - - nginx-upstream-fair - Homepage: https://github.com/gnosek/nginx-upstream-fair - Version: a18b409 - Patch: dynamic-module.patch - Patch: openssl-1.1.0.patch - Patch: drop-default-port.patch - - nchan - Homepage: https://github.com/slact/nchan - Version: 1.0.8 - - nginx-upload-progress - Homepage: https://github.com/masterzen/nginx-upload-progress-module - rm -r debian/nginx-upload-progress/test - Version: v0.9.2 - - nginx-cache-purge - Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ - Version: 2.3 - Patch: dynamic-module.patch - Patch: segfault-1.11.6.patch - - nginx-dav-ext-module - Homepage: https://github.com/arut/nginx-dav-ext-module - Version: v0.0.3 - Patch: dynamic-module.patch - - ngx-fancyindex - Homepage: https://github.com/aperezdc/ngx-fancyindex - Version: v0.4.1 - - ngx_http_substitutions_filter_module - Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module - Version: v0.6.4 - Patch: dynamic-module.patch - - nginx-rtmp - Homepage: https://github.com/arut/nginx-rtmp-module - rm -r debian/modules/nginx-rtmp-module/test - Version: v1.1.11 diff --git a/debian/modules/control b/debian/modules/control new file mode 100644 index 0000000..5f67e38 --- /dev/null +++ b/debian/modules/control @@ -0,0 +1,71 @@ +Module: http-headers-more-filter +Homepage: https://github.com/agentzh/headers-more-nginx-module +Version: v0.32 +Files-Excluded: .gitignore .gitattributes .travis.yml + +Module: http-ndk +Homepage: https://github.com/simpl/ngx_devel_kit/ +Version: v0.3.0 + +Module: http-auth-pam +Homepage: https://github.com/stogh/ngx_http_auth_pam_module +Version: v1.5.1 + +Module: http-echo +Homepage: https://github.com/agentzh/echo-nginx-module +Version: v0.60 +Files-Excluded: .gitignore .gitattributes .travis.yml +Patch: build-nginx-1.11.11.patch + +Module: http-lua +Homepage: https://github.com/openresty/lua-nginx-module +Version: v0.10.10 +Patch: + openssl-1.1.0.patch + discover-luajit-2.1.patch +Files-Excluded: .gitignore .gitattributes .travis.yml .github + +Module: http-upstream-fair +Homepage: https://github.com/gnosek/nginx-upstream-fair +Version: a18b409 +Patch: + dynamic-module.patch + openssl-1.1.0.patch + drop-default-port.patch + +Module: nchan +Homepage: https://github.com/slact/nchan +Version: v1.0.8 + +Module: http-uploadprogress +Homepage: https://github.com/masterzen/nginx-upload-progress-module +Files-Excluded: test +Version: v0.9.2 + +Module: http-cache-purge +Homepage: https://github.com/FRiCKLE/ngx_cache_purge/ +Version: 2.3 +Patch: + dynamic-module.patch + segfault-1.11.6.patch + +Module: http-dav-ext +Homepage: https://github.com/arut/nginx-dav-ext-module +Version: v0.0.3 +Patch: dynamic-module.patch + +Module: http-fancyindex +Homepage: https://github.com/aperezdc/ngx-fancyindex +Version: v0.4.1 +Files-Excluded: .gitignore .travis.yml + +Module: http-subs-filter +Homepage: https://github.com/yaoweibin/ngx_http_substitutions_filter_module +Version: v0.6.4 +Patch: dynamic-module.patch + +Module: rtmp +Homepage: https://github.com/arut/nginx-rtmp-module +Files-Excluded: test +Version: v1.1.11 + diff --git a/debian/modules/uupdate b/debian/modules/uupdate new file mode 100755 index 0000000..98a5f8b --- /dev/null +++ b/debian/modules/uupdate @@ -0,0 +1,10 @@ +#!/bin/bash + +# debian/modules/uupdate - simple tar wrapper used by uscan to upgrade modules source + +MOD_TAR_NAME=$2 +MOD_TAR_VER=$4 +DESTDIR=debian/modules/$1 + +tar --strip-components=1 -xf ../$MOD_TAR_NAME-$MOD_TAR_VER.tar.gz -C $DESTDIR +echo $MOD_TAR_VER > /tmp/ngx_uupdate_version_$1 diff --git a/debian/modules/watch/http-auth-pam b/debian/modules/watch/http-auth-pam new file mode 100644 index 0000000..eac2f73 --- /dev/null +++ b/debian/modules/watch/http-auth-pam @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-auth-pam-$1.tar.gz%" \ + https://github.com/stogh/ngx_http_auth_pam_module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-auth-pam ngx-mod-http-auth-pam diff --git a/debian/modules/watch/http-cache-purge b/debian/modules/watch/http-cache-purge new file mode 100644 index 0000000..2566801 --- /dev/null +++ b/debian/modules/watch/http-cache-purge @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-cache-purge-$1.tar.gz%" \ + https://github.com/FRiCKLE/ngx_cache_purge/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-cache-purge ngx-mod-cache-purge diff --git a/debian/modules/watch/http-dav-ext b/debian/modules/watch/http-dav-ext new file mode 100644 index 0000000..d704cfc --- /dev/null +++ b/debian/modules/watch/http-dav-ext @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-dav-ext-$1.tar.gz%" \ + https://github.com/arut/nginx-dav-ext-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-dav-ext ngx-mod-dav-ext diff --git a/debian/modules/watch/http-echo b/debian/modules/watch/http-echo new file mode 100644 index 0000000..615532b --- /dev/null +++ b/debian/modules/watch/http-echo @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-echo-$1.tar.gz%" \ + https://github.com/agentzh/echo-nginx-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-echo ngx-mod-echo diff --git a/debian/modules/watch/http-fancyindex b/debian/modules/watch/http-fancyindex new file mode 100644 index 0000000..72435fd --- /dev/null +++ b/debian/modules/watch/http-fancyindex @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-fancyindex-$1.tar.gz%" \ + https://github.com/aperezdc/ngx-fancyindex/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-fancyindex ngx-mod-fancyindex diff --git a/debian/modules/watch/http-headers-more-filter b/debian/modules/watch/http-headers-more-filter new file mode 100644 index 0000000..cfe5fc9 --- /dev/null +++ b/debian/modules/watch/http-headers-more-filter @@ -0,0 +1,4 @@ +version=4 +opts="uversionmangle=s/0.261/0.26.1/,dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-headers-more-$1.tar.gz%" \ + https://github.com/agentzh/headers-more-nginx-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-headers-more-filter ngx-mod-headers-more diff --git a/debian/modules/watch/http-lua b/debian/modules/watch/http-lua new file mode 100644 index 0000000..7f1718f --- /dev/null +++ b/debian/modules/watch/http-lua @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%lua-nginx-module-$1.tar.gz%" \ + https://github.com/openresty/lua-nginx-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-lua lua-nginx-module diff --git a/debian/modules/watch/http-ndk b/debian/modules/watch/http-ndk new file mode 100644 index 0000000..43f0cbd --- /dev/null +++ b/debian/modules/watch/http-ndk @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-devel-kit-$1.tar.gz%" \ + https://github.com/simpl/ngx_devel_kit/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-ndk ngx-mod-devel-kit diff --git a/debian/modules/watch/http-subs-filter b/debian/modules/watch/http-subs-filter new file mode 100644 index 0000000..cca3e05 --- /dev/null +++ b/debian/modules/watch/http-subs-filter @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-substitutions-filter-$1.tar.gz%" \ + https://github.com/yaoweibin/ngx_http_substitutions_filter_module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-subs-filter ngx-mod-http-substitutions-filter diff --git a/debian/modules/watch/http-uploadprogress b/debian/modules/watch/http-uploadprogress new file mode 100644 index 0000000..7c0b7cf --- /dev/null +++ b/debian/modules/watch/http-uploadprogress @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-upload-progress-$1.tar.gz%" \ + https://github.com/masterzen/nginx-upload-progress-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-uploadprogress ngx-mod-upload-progress diff --git a/debian/modules/watch/nchan b/debian/modules/watch/nchan new file mode 100644 index 0000000..6b95884 --- /dev/null +++ b/debian/modules/watch/nchan @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-nchan-$1.tar.gz%" \ + https://github.com/slact/nchan/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate nchan ngx-mod-nchan diff --git a/debian/modules/watch/rtmp b/debian/modules/watch/rtmp new file mode 100644 index 0000000..f8137a2 --- /dev/null +++ b/debian/modules/watch/rtmp @@ -0,0 +1,4 @@ +version=4 +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-rtmp-$1.tar.gz%" \ + https://github.com/arut/nginx-rtmp-module/tags \ + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate rtmp ngx-mod-rtmp diff --git a/debian/ngxmod b/debian/ngxmod new file mode 100755 index 0000000..f8180d1 --- /dev/null +++ b/debian/ngxmod @@ -0,0 +1,156 @@ +#!/usr/bin/env python +''' +ngxmod - nginx modules management helper script + +Usage: + ngxmod + +Subcommands: + + uscan - scan/watch upstream nginx module sources for new releases + + It runs uscan for each nginx module listed in debian/modules/control. + + If a new version is available, it will ask you if you want to upgrade. + If you agree it will use uscan to download the tarball, place it in the nginx + source's parent directory and unpack it using modules/uupdate to upgrade + the module's source. + + After the upgrade, it will remove the files listed in the Files-Excluded + field and finally it will commit the changes. +''' + +import deb822 +import os +import sys +import re +from subprocess import call + +MODULES_PATH = 'modules/' +MODULES_CTRL = os.path.join(MODULES_PATH, 'control') + +def prompt(query): + ''' + Ask the given query and wait for an y/N answer. + + :query: The query + :returns: The yes (True) or no (False) answer + ''' + sys.stdout.write('%s [y/N]: ' % query) + choice = raw_input().lower() + + return choice == 'y' + + +def upgrade_module(mi, watchfile): + ''' + Upgrade the given module using uscan and the custom modules/uupdate. + After the upgrade, remove the Files-Excluded. + + :param mi: modules/control info for the module + :param watchfile: The watchfile of the module + :returns: The new module version + ''' + uscan_upgrade_cmd = [ + 'uscan', '--upstream-version', mi['Version'], + '--watchfile', 'debian/%s' % watchfile, '--no-symlink' + ] + upgrade_ret = call(uscan_upgrade_cmd, stdout=open(os.devnull, 'w')) + + if 'Files-Excluded' in mi and upgrade_ret == 0: + print 'Removing Files-Excluded: %s' % mi['Files-Excluded'] + + files = re.split('\s+', mi['Files-Excluded']) + files = filter(None, files) + abs_files = ['%s%s/%s' % (MODULES_PATH, mi['Module'], f) for f in files] + + rm_cmd = ['rm', '-r'] + rm_cmd.extend(abs_files) + + call(rm_cmd) + + return open('/tmp/ngx_uupdate_version_%s' % mi['Module']).read().rstrip() + + +def update_module_version(mi, new_ver): + ''' + Update the given module's version in modules/control. + + :param mi: modules/control info for the module + :param new_ver: The new module version + ''' + modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) + modules_ctrl_new = '%s%s' % (MODULES_CTRL, '.new') + with open(modules_ctrl_new, 'w') as c: + for m in modules_info: + if mi['Module'] == m['Module']: + m['Version'] = re.sub('[^v]+', new_ver, m['Version']) + + c.write(m.dump() + '\n') + c.closed + os.rename(modules_ctrl_new, MODULES_CTRL) + + +def commit_module(mi, new_ver): + ''' + Git-commit the given module's upgraded source. + + :param mi: modules/control info for the module + :param new_ver: The new module version + ''' + module_name = mi['Module'] + module_path = os.path.join(MODULES_PATH, module_name) + + git_add_cmd = ['git', 'add', module_path, MODULES_CTRL] + call(git_add_cmd) + + commit_msg = 'Update %s to v%s' % (module_name, new_ver) + git_commit_cmd = ['git', 'commit', '-m', commit_msg] + call(git_commit_cmd) + + +def usage(): + print(""" +Usage: + ngxmod + +Subcommands: + + uscan - scan/watch upstream nginx module sources for new releases +""") + + +def main(): + modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) + + for mi in modules_info: + sys.stdout.write('Uscanning %s...' % mi['Module']) + sys.stdout.flush() + + watchfile = os.path.join(MODULES_PATH, 'watch', mi['Module']) + + if not os.path.isfile(watchfile): + print 'no watchfile available.' + continue + + uscan_check_cmd = [ + 'uscan', '--upstream-version', mi['Version'], + '--watchfile', watchfile, '--package', + mi['Module'] + ] + check_ret = call(uscan_check_cmd) + + if check_ret == 0: + if prompt('Do you want to upgrade %s?' % mi['Module']): + new_module_ver = upgrade_module(mi, watchfile) + update_module_version(mi, new_module_ver) + commit_module(mi, new_module_ver) + else: + print 'up-to-date.' + + +if __name__ == '__main__': + if len(sys.argv) == 2 and sys.argv[1] == 'uscan': + main() + else: + usage() From 7f899937abcb400b8fc8e5d014ca16af9705eeab Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Mon, 11 Dec 2017 11:46:58 +0200 Subject: [PATCH 044/414] Bits & pieces for ngxmod o Drop d/m/uupdate in favor of ngxmod uupdate subcommand. While at it, take advantage of the canonical module names and drop the last argument. o Move unpacking & commit to uupdate subcommand, that way we don't to have to communicate the upstream version with ngxmod uscan. o Move around a few things, and switch to argparse. --- debian/modules/uupdate | 10 - debian/modules/watch/http-auth-pam | 4 +- debian/modules/watch/http-cache-purge | 4 +- debian/modules/watch/http-dav-ext | 4 +- debian/modules/watch/http-echo | 4 +- debian/modules/watch/http-fancyindex | 4 +- debian/modules/watch/http-headers-more-filter | 4 +- debian/modules/watch/http-lua | 4 +- debian/modules/watch/http-ndk | 4 +- debian/modules/watch/http-subs-filter | 4 +- debian/modules/watch/http-uploadprogress | 4 +- debian/modules/watch/nchan | 4 +- debian/modules/watch/rtmp | 4 +- debian/ngxmod | 278 +++++++++++------- 14 files changed, 194 insertions(+), 142 deletions(-) delete mode 100755 debian/modules/uupdate diff --git a/debian/modules/uupdate b/debian/modules/uupdate deleted file mode 100755 index 98a5f8b..0000000 --- a/debian/modules/uupdate +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# debian/modules/uupdate - simple tar wrapper used by uscan to upgrade modules source - -MOD_TAR_NAME=$2 -MOD_TAR_VER=$4 -DESTDIR=debian/modules/$1 - -tar --strip-components=1 -xf ../$MOD_TAR_NAME-$MOD_TAR_VER.tar.gz -C $DESTDIR -echo $MOD_TAR_VER > /tmp/ngx_uupdate_version_$1 diff --git a/debian/modules/watch/http-auth-pam b/debian/modules/watch/http-auth-pam index eac2f73..3fb5a27 100644 --- a/debian/modules/watch/http-auth-pam +++ b/debian/modules/watch/http-auth-pam @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-auth-pam-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-auth-pam-$1.tar.gz%" \ https://github.com/stogh/ngx_http_auth_pam_module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-auth-pam ngx-mod-http-auth-pam + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-auth-pam diff --git a/debian/modules/watch/http-cache-purge b/debian/modules/watch/http-cache-purge index 2566801..e2458f2 100644 --- a/debian/modules/watch/http-cache-purge +++ b/debian/modules/watch/http-cache-purge @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-cache-purge-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-cache-purge-$1.tar.gz%" \ https://github.com/FRiCKLE/ngx_cache_purge/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-cache-purge ngx-mod-cache-purge + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-cache-purge diff --git a/debian/modules/watch/http-dav-ext b/debian/modules/watch/http-dav-ext index d704cfc..064766a 100644 --- a/debian/modules/watch/http-dav-ext +++ b/debian/modules/watch/http-dav-ext @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-dav-ext-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-dav-ext-$1.tar.gz%" \ https://github.com/arut/nginx-dav-ext-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-dav-ext ngx-mod-dav-ext + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-dav-ext diff --git a/debian/modules/watch/http-echo b/debian/modules/watch/http-echo index 615532b..3d44f5d 100644 --- a/debian/modules/watch/http-echo +++ b/debian/modules/watch/http-echo @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-echo-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-echo-$1.tar.gz%" \ https://github.com/agentzh/echo-nginx-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-echo ngx-mod-echo + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-echo diff --git a/debian/modules/watch/http-fancyindex b/debian/modules/watch/http-fancyindex index 72435fd..5833ccd 100644 --- a/debian/modules/watch/http-fancyindex +++ b/debian/modules/watch/http-fancyindex @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-fancyindex-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-fancyindex-$1.tar.gz%" \ https://github.com/aperezdc/ngx-fancyindex/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-fancyindex ngx-mod-fancyindex + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-fancyindex diff --git a/debian/modules/watch/http-headers-more-filter b/debian/modules/watch/http-headers-more-filter index cfe5fc9..b0cae5c 100644 --- a/debian/modules/watch/http-headers-more-filter +++ b/debian/modules/watch/http-headers-more-filter @@ -1,4 +1,4 @@ version=4 -opts="uversionmangle=s/0.261/0.26.1/,dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-headers-more-$1.tar.gz%" \ +opts="uversionmangle=s/0.261/0.26.1/,dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-headers-more-filter-$1.tar.gz%" \ https://github.com/agentzh/headers-more-nginx-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-headers-more-filter ngx-mod-headers-more + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-headers-more-filter diff --git a/debian/modules/watch/http-lua b/debian/modules/watch/http-lua index 7f1718f..193d824 100644 --- a/debian/modules/watch/http-lua +++ b/debian/modules/watch/http-lua @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%lua-nginx-module-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-lua-$1.tar.gz%" \ https://github.com/openresty/lua-nginx-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-lua lua-nginx-module + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-lua diff --git a/debian/modules/watch/http-ndk b/debian/modules/watch/http-ndk index 43f0cbd..f359136 100644 --- a/debian/modules/watch/http-ndk +++ b/debian/modules/watch/http-ndk @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-devel-kit-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-ndk-$1.tar.gz%" \ https://github.com/simpl/ngx_devel_kit/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-ndk ngx-mod-devel-kit + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-ndk diff --git a/debian/modules/watch/http-subs-filter b/debian/modules/watch/http-subs-filter index cca3e05..2d37540 100644 --- a/debian/modules/watch/http-subs-filter +++ b/debian/modules/watch/http-subs-filter @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-http-substitutions-filter-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-subs-filter-$1.tar.gz%" \ https://github.com/yaoweibin/ngx_http_substitutions_filter_module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-subs-filter ngx-mod-http-substitutions-filter + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-subs-filter diff --git a/debian/modules/watch/http-uploadprogress b/debian/modules/watch/http-uploadprogress index 7c0b7cf..cccba98 100644 --- a/debian/modules/watch/http-uploadprogress +++ b/debian/modules/watch/http-uploadprogress @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-upload-progress-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-http-uploadprogress-$1.tar.gz%" \ https://github.com/masterzen/nginx-upload-progress-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate http-uploadprogress ngx-mod-upload-progress + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate http-uploadprogress diff --git a/debian/modules/watch/nchan b/debian/modules/watch/nchan index 6b95884..199ab19 100644 --- a/debian/modules/watch/nchan +++ b/debian/modules/watch/nchan @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-nchan-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-nchan-$1.tar.gz%" \ https://github.com/slact/nchan/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate nchan ngx-mod-nchan + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate nchan diff --git a/debian/modules/watch/rtmp b/debian/modules/watch/rtmp index f8137a2..2a95f4c 100644 --- a/debian/modules/watch/rtmp +++ b/debian/modules/watch/rtmp @@ -1,4 +1,4 @@ version=4 -opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%ngx-mod-rtmp-$1.tar.gz%" \ +opts="dversionmangle=s/v//,filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%libnginx-mod-rtmp-$1.tar.gz%" \ https://github.com/arut/nginx-rtmp-module/tags \ - (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/modules/uupdate rtmp ngx-mod-rtmp + (?:.*?/)?v?(\d[\d.]*)\.tar\.gz debian debian/ngxmod uupdate rtmp diff --git a/debian/ngxmod b/debian/ngxmod index f8180d1..7eacaa5 100755 --- a/debian/ngxmod +++ b/debian/ngxmod @@ -1,130 +1,156 @@ #!/usr/bin/env python -''' -ngxmod - nginx modules management helper script +""" +Handy Debian nginx module management helper +""" -Usage: - ngxmod - -Subcommands: - - uscan - scan/watch upstream nginx module sources for new releases - - It runs uscan for each nginx module listed in debian/modules/control. - - If a new version is available, it will ask you if you want to upgrade. - If you agree it will use uscan to download the tarball, place it in the nginx - source's parent directory and unpack it using modules/uupdate to upgrade - the module's source. - - After the upgrade, it will remove the files listed in the Files-Excluded - field and finally it will commit the changes. -''' - -import deb822 +import argparse import os -import sys import re +import shutil +import sys +import tarfile +import tempfile + from subprocess import call -MODULES_PATH = 'modules/' -MODULES_CTRL = os.path.join(MODULES_PATH, 'control') +import deb822 + +DEBIAN_PATH = os.path.dirname(os.path.realpath(__file__)) +MODULES_PATH = os.path.join(DEBIAN_PATH, 'modules') +CTRL_PATH = os.path.join(MODULES_PATH, 'control') +CTRL = [p for p in deb822.Deb822.iter_paragraphs(file(CTRL_PATH))] + + +def ctrl(name): + "Return deb822 paragraph for the selected module" + global CTRL + + for m in CTRL: + if m['Module'] == name: + return m + + +def update_ctrl(): + "Save current control to disk" + global CTRL + + new_ctrl = CTRL_PATH + '.new' + with open(new_ctrl, 'w') as c: + for m in CTRL: + c.write(m.dump() + '\n') + + os.rename(new_ctrl, CTRL_PATH) + def prompt(query): - ''' + """ Ask the given query and wait for an y/N answer. :query: The query :returns: The yes (True) or no (False) answer - ''' + """ sys.stdout.write('%s [y/N]: ' % query) choice = raw_input().lower() return choice == 'y' -def upgrade_module(mi, watchfile): - ''' - Upgrade the given module using uscan and the custom modules/uupdate. - After the upgrade, remove the Files-Excluded. - - :param mi: modules/control info for the module - :param watchfile: The watchfile of the module - :returns: The new module version - ''' - uscan_upgrade_cmd = [ - 'uscan', '--upstream-version', mi['Version'], - '--watchfile', 'debian/%s' % watchfile, '--no-symlink' - ] - upgrade_ret = call(uscan_upgrade_cmd, stdout=open(os.devnull, 'w')) - - if 'Files-Excluded' in mi and upgrade_ret == 0: - print 'Removing Files-Excluded: %s' % mi['Files-Excluded'] - - files = re.split('\s+', mi['Files-Excluded']) - files = filter(None, files) - abs_files = ['%s%s/%s' % (MODULES_PATH, mi['Module'], f) for f in files] - - rm_cmd = ['rm', '-r'] - rm_cmd.extend(abs_files) - - call(rm_cmd) - - return open('/tmp/ngx_uupdate_version_%s' % mi['Module']).read().rstrip() - - -def update_module_version(mi, new_ver): - ''' - Update the given module's version in modules/control. - - :param mi: modules/control info for the module - :param new_ver: The new module version - ''' - modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) - modules_ctrl_new = '%s%s' % (MODULES_CTRL, '.new') - with open(modules_ctrl_new, 'w') as c: - for m in modules_info: - if mi['Module'] == m['Module']: - m['Version'] = re.sub('[^v]+', new_ver, m['Version']) - - c.write(m.dump() + '\n') - c.closed - os.rename(modules_ctrl_new, MODULES_CTRL) - - -def commit_module(mi, new_ver): - ''' +def commit(module, version): + """ Git-commit the given module's upgraded source. - :param mi: modules/control info for the module - :param new_ver: The new module version - ''' - module_name = mi['Module'] - module_path = os.path.join(MODULES_PATH, module_name) + :param module: module name + :param version: The updated module version + """ + module_path = os.path.join(MODULES_PATH, module) - git_add_cmd = ['git', 'add', module_path, MODULES_CTRL] + git_add_cmd = ['git', 'add', '--all', module_path, CTRL_PATH] call(git_add_cmd) - commit_msg = 'Update %s to v%s' % (module_name, new_ver) - git_commit_cmd = ['git', 'commit', '-m', commit_msg] + commit_msg = '%s: Upgrade to v%s' % (module, version) + git_commit_cmd = [ + 'git', 'commit', '-m', commit_msg, + '--', module_path, CTRL_PATH] call(git_commit_cmd) -def usage(): - print(""" -Usage: - ngxmod +def unpack(module, version, exclude): + "Unpack upstream tar file into module path" -Subcommands: + tar_gz = os.path.join( + "..", "libnginx-mod-%s-%s.tar.gz" % (module, version)) + if not os.path.exists(tar_gz): + print "%s doesn't exist!" % tar_gz + exit(1) - uscan - scan/watch upstream nginx module sources for new releases -""") + module_path = os.path.join(MODULES_PATH, module) + tmpdir = tempfile.mkdtemp(prefix="libnginx-mod-%s-%s." % (module, version)) + with tarfile.open(tar_gz) as tar: + members = tar.getmembers() + + # stip top-level directory from tar + topdir = members[0] + if not topdir or not topdir.isdir(): + print "No top directory found!" + exit(1) + + topdir = members[0].path + if any(topdir not in ti.path for ti in members): + print "Not all files are under the top directory '%s'" % topdir + exit(1) + + def remove_topdir_prefix(tarinfo): + "Strip top directory" + tarinfo.path = os.path.relpath(tarinfo.path, topdir) + return tarinfo + members = [remove_topdir_prefix(tarinfo) for tarinfo in members] + tar.extractall(path=tmpdir, members=members) + + shutil.rmtree(module_path) + shutil.move(tmpdir, module_path) + + for e in exclude: + print "Removing %s..." % e + abspath = os.path.join(module_path, e) + if os.path.isdir(abspath): + shutil.rmtree(abspath) + else: + os.remove(abspath) -def main(): - modules_info = deb822.Deb822.iter_paragraphs(file(MODULES_CTRL)) +def cmd_uupdate(args): + "Internal uupdate helper, upgrades & commits the given module" + c = ctrl(args.module) - for mi in modules_info: - sys.stdout.write('Uscanning %s...' % mi['Module']) + exclude = [] + if 'Files-Excluded' in c: + exclude = c['Files-Excluded'].split() + + unpack(args.module, args.upstream_version, exclude) + + # change ctrl version + c['Version'] = re.sub('[^v]+', args.upstream_version, c['Version']) + update_ctrl() + + commit(args.module, args.upstream_version) + + +def cmd_uscan(args): + """ + Run uscan for each nginx module listed in debian/modules/control. + + If a new version is found, it will be downloaded & unpacked to the proper + debian/modules/MODULE path. + + After the upgrade, all files listed in the Files-Excluded: control field + will be removed, debian/modules/control version will be updated and all + changes will be commited to git. + """ + global CTRL + + # For every module that has watchfile... + for mi in CTRL: + sys.stdout.write('Uscanning %s: ' % mi['Module']) sys.stdout.flush() watchfile = os.path.join(MODULES_PATH, 'watch', mi['Module']) @@ -133,24 +159,60 @@ def main(): print 'no watchfile available.' continue + # Check uscan_check_cmd = [ 'uscan', '--upstream-version', mi['Version'], '--watchfile', watchfile, '--package', mi['Module'] ] - check_ret = call(uscan_check_cmd) + if call(uscan_check_cmd) != 0: + print 'up-to-date' + continue - if check_ret == 0: - if prompt('Do you want to upgrade %s?' % mi['Module']): - new_module_ver = upgrade_module(mi, watchfile) - update_module_version(mi, new_module_ver) - commit_module(mi, new_module_ver) - else: - print 'up-to-date.' + # Ask + if not prompt('Do you want to upgrade %s?' % mi['Module']): + continue + + # Upgrade + uscan_upgrade_cmd = [ + 'uscan', '--upstream-version', mi['Version'], + '--watchfile', watchfile, '--no-symlink' + ] + if call(uscan_upgrade_cmd, stdout=open(os.devnull, 'w')) != 0: + print "Uscan for %s failed!" % mi['Module'] + exit(1) + + +def main(): + """ngxmod main""" + + parser = argparse.ArgumentParser( + description=__doc__) + cmds = parser.add_subparsers(title="Commands") + + import textwrap + uscan_cmd = cmds.add_parser( + "uscan", + help="scan/watch upstream nginx module sources for new releases", + description=textwrap.dedent(cmd_uscan.__doc__), + formatter_class=argparse.RawDescriptionHelpFormatter) + uscan_cmd.set_defaults(func=cmd_uscan) + + uupdate_cmd = cmds.add_parser( + "uupdate", + help=cmd_uupdate.__doc__, + description=cmd_uupdate.__doc__) + uupdate_cmd.add_argument("module", metavar="MODULE", help="Module name") + uupdate_cmd.add_argument( + "--upstream-version", + required=True, + metavar="VERSION", + help="Upstream version") + uupdate_cmd.set_defaults(func=cmd_uupdate) + + args = parser.parse_args() + args.func(args) if __name__ == '__main__': - if len(sys.argv) == 2 and sys.argv[1] == 'uscan': - main() - else: - usage() + main() From 33799993fc8fbe4d3aca32b6518cc3a01d4729b7 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:22:21 +0200 Subject: [PATCH 045/414] http-headers-more-filter: Upgrade to 0.33 --- debian/modules/control | 2 +- .../http-headers-more-filter/README.markdown | 40 ++++-- .../src/ngx_http_headers_more_headers_in.c | 63 +++++---- .../http-headers-more-filter/t/builtin.t | 1 - .../http-headers-more-filter/t/input-conn.t | 1 - .../http-headers-more-filter/t/input-ua.t | 1 - .../http-headers-more-filter/t/input.t | 42 +++++- .../http-headers-more-filter/t/phase.t | 1 - .../http-headers-more-filter/t/sanity.t | 1 - .../http-headers-more-filter/t/subrequest.t | 1 - .../http-headers-more-filter/t/unused.t | 1 - .../modules/http-headers-more-filter/t/vars.t | 1 - .../valgrind.suppress | 126 ++++-------------- 13 files changed, 134 insertions(+), 147 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index 5f67e38..71c63eb 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -1,6 +1,6 @@ Module: http-headers-more-filter Homepage: https://github.com/agentzh/headers-more-nginx-module -Version: v0.32 +Version: v0.33 Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-ndk diff --git a/debian/modules/http-headers-more-filter/README.markdown b/debian/modules/http-headers-more-filter/README.markdown index d584461..452ef1f 100644 --- a/debian/modules/http-headers-more-filter/README.markdown +++ b/debian/modules/http-headers-more-filter/README.markdown @@ -36,7 +36,7 @@ Table of Contents Version ======= -This document describes headers-more-nginx-module [v0.32](https://github.com/openresty/headers-more-nginx-module/tags) released on 4 November 2016. +This document describes headers-more-nginx-module [v0.33](https://github.com/openresty/headers-more-nginx-module/tags) released on 3 November 2017. Synopsis ======== @@ -248,7 +248,8 @@ or See [more_set_headers](#more_set_headers) for more details. -Wildcard `*` can also be used to specify a header name pattern. For example, the following directive effectively clears *any* output headers starting by "`X-Hidden-`": +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 @@ -298,25 +299,40 @@ In fact, ```nginx - more_clear_input_headers -s 404 -t 'text/plain' Foo Baz; + more_clear_input_headers -t 'text/plain' Foo Baz; ``` is exactly equivalent to ```nginx - more_set_input_headers -s 404 -t 'text/plain' "Foo: " "Baz: "; + more_set_input_headers -t 'text/plain' "Foo: " "Baz: "; ``` or ```nginx - more_set_input_headers -s 404 -t 'text/plain' Foo Baz + 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 @@ -331,13 +347,13 @@ Installation ============ 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: +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.11.2.tar.gz' - tar -xzvf nginx-1.11.2.tar.gz - cd nginx-1.11.2/ + 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 \ @@ -366,6 +382,8 @@ 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) @@ -479,7 +497,7 @@ You'll be very welcomed to submit patches to the [author](#author) or just ask f Authors ======= -* Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, CloudFlare Inc. +* 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. @@ -491,7 +509,7 @@ 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-2014, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. Copyright (c) 2010-2013, Bernd Dorn. diff --git a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c index bdea8de..c3eb8f7 100644 --- a/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c +++ b/debian/modules/http-headers-more-filter/src/ngx_http_headers_more_headers_in.c @@ -243,42 +243,59 @@ retry: i = 0; } - if (h[i].key.len == hv->key.len + if (!hv->wildcard + && h[i].key.len == hv->key.len && ngx_strncasecmp(h[i].key.data, hv->key.data, h[i].key.len) == 0) { - if (value->len == 0 || (matched && matched != &h[i])) { - h[i].hash = 0; + goto matched; + } - rc = ngx_http_headers_more_rm_header_helper( - &r->headers_in.headers, part, i); + 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; + } - ngx_http_headers_more_assert( - !(r->headers_in.headers.part.next == NULL - && r->headers_in.headers.last - != &r->headers_in.headers.part)); + /* not matched */ + continue; - if (rc == NGX_OK) { - if (output_header) { - *output_header = NULL; - } +matched: - goto retry; + 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; } - return NGX_ERROR; + goto retry; } - h[i].value = *value; + return NGX_ERROR; + } - if (output_header) { - *output_header = &h[i]; - dd("setting existing builtin input header"); - } + h[i].value = *value; - if (matched == NULL) { - matched = &h[i]; - } + if (output_header) { + *output_header = &h[i]; + dd("setting existing builtin input header"); + } + + if (matched == NULL) { + matched = &h[i]; } } diff --git a/debian/modules/http-headers-more-filter/t/builtin.t b/debian/modules/http-headers-more-filter/t/builtin.t index f2b5c34..27b20af 100644 --- a/debian/modules/http-headers-more-filter/t/builtin.t +++ b/debian/modules/http-headers-more-filter/t/builtin.t @@ -336,4 +336,3 @@ hello Vary: hello --- response_body hello - diff --git a/debian/modules/http-headers-more-filter/t/input-conn.t b/debian/modules/http-headers-more-filter/t/input-conn.t index a32d4e1..f53e80f 100644 --- a/debian/modules/http-headers-more-filter/t/input-conn.t +++ b/debian/modules/http-headers-more-filter/t/input-conn.t @@ -135,4 +135,3 @@ content: conn type: 0 connection: bad --- no_error_log [error] - diff --git a/debian/modules/http-headers-more-filter/t/input-ua.t b/debian/modules/http-headers-more-filter/t/input-ua.t index 56d2222..da9a60d 100644 --- a/debian/modules/http-headers-more-filter/t/input-ua.t +++ b/debian/modules/http-headers-more-filter/t/input-ua.t @@ -626,4 +626,3 @@ content: konqueror: 1 User-Agent: Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.10 (like Gecko) (Kubuntu) --- no_error_log [error] - diff --git a/debian/modules/http-headers-more-filter/t/input.t b/debian/modules/http-headers-more-filter/t/input.t index 0b8989f..01ae73f 100644 --- a/debian/modules/http-headers-more-filter/t/input.t +++ b/debian/modules/http-headers-more-filter/t/input.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket; # 'no_plan'; repeat_each(2); -plan tests => repeat_each() * 124; +plan tests => repeat_each() * 128; no_long_string(); #no_diff; @@ -1289,3 +1289,43 @@ X-Forwarded-For: 8.8.8.8 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/debian/modules/http-headers-more-filter/t/phase.t b/debian/modules/http-headers-more-filter/t/phase.t index 343d2e5..11183db 100644 --- a/debian/modules/http-headers-more-filter/t/phase.t +++ b/debian/modules/http-headers-more-filter/t/phase.t @@ -23,4 +23,3 @@ __DATA__ X-Foo: Blah --- response_body_like: 403 Forbidden --- error_code: 403 - diff --git a/debian/modules/http-headers-more-filter/t/sanity.t b/debian/modules/http-headers-more-filter/t/sanity.t index e316cac..d06f5dc 100644 --- a/debian/modules/http-headers-more-filter/t/sanity.t +++ b/debian/modules/http-headers-more-filter/t/sanity.t @@ -565,4 +565,3 @@ hi --- response_body ok --- http09 - diff --git a/debian/modules/http-headers-more-filter/t/subrequest.t b/debian/modules/http-headers-more-filter/t/subrequest.t index 34e84c9..9443eca 100644 --- a/debian/modules/http-headers-more-filter/t/subrequest.t +++ b/debian/modules/http-headers-more-filter/t/subrequest.t @@ -66,4 +66,3 @@ main: dog --- response_headers ! Host --- skip_nginx: 3: < 0.7.46 - diff --git a/debian/modules/http-headers-more-filter/t/unused.t b/debian/modules/http-headers-more-filter/t/unused.t index 1f35adc..c51f91c 100644 --- a/debian/modules/http-headers-more-filter/t/unused.t +++ b/debian/modules/http-headers-more-filter/t/unused.t @@ -172,4 +172,3 @@ bar headers more header handler [error] --- log_level: debug - diff --git a/debian/modules/http-headers-more-filter/t/vars.t b/debian/modules/http-headers-more-filter/t/vars.t index 426c68c..04c75c3 100644 --- a/debian/modules/http-headers-more-filter/t/vars.t +++ b/debian/modules/http-headers-more-filter/t/vars.t @@ -56,4 +56,3 @@ hi dog --- response_headers Host: - diff --git a/debian/modules/http-headers-more-filter/valgrind.suppress b/debian/modules/http-headers-more-filter/valgrind.suppress index bba7217..d51de70 100644 --- a/debian/modules/http-headers-more-filter/valgrind.suppress +++ b/debian/modules/http-headers-more-filter/valgrind.suppress @@ -1,40 +1,9 @@ -{ - -Memcheck:Cond -fun:lj_str_new -} { - Memcheck:Cond - fun:lj_str_new - fun:lua_pushlstring -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_pushlstring -} -{ - -Memcheck:Leak -fun:malloc -fun:ngx_alloc -obj:* -} -{ - -Memcheck:Leak -fun:malloc -fun:ngx_alloc -} -{ - -Memcheck:Leak -fun:malloc -fun:ngx_alloc -fun:ngx_palloc_large -fun:ngx_palloc + Memcheck:Leak + fun:malloc + fun:ngx_alloc + obj:* } { @@ -44,27 +13,6 @@ fun:ngx_palloc fun:ngx_calloc fun:ngx_event_process_init } -{ - -Memcheck:Addr4 -fun:lj_str_new -fun:lua_pushlstring -fun:ngx_http_lua_get_output_header -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_getfield - fun:ngx_http_lua_cache_load_code -} -{ - - Memcheck:Addr4 - fun:lj_str_new - fun:lua_setfield - fun:ngx_http_lua_cache_store_code -} { Memcheck:Leak @@ -72,34 +20,12 @@ fun:ngx_http_lua_get_output_header fun:ngx_alloc fun:ngx_event_process_init } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:(below main) -} { Memcheck:Param epoll_ctl(event) fun:epoll_ctl } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_create_pool -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_palloc_large -} { Memcheck:Cond @@ -108,22 +34,6 @@ fun:ngx_http_lua_get_output_header fun:ngx_log_error_core fun:ngx_http_charset_header_filter } -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_pnalloc -} -{ - - Memcheck:Leak - fun:malloc - fun:ngx_alloc - fun:ngx_malloc - fun:ngx_palloc -} { nginx-core-process-init Memcheck:Leak @@ -185,15 +95,6 @@ fun:ngx_http_lua_get_output_header fun:ngx_epoll_process_events fun:ngx_process_events_and_timers } -{ - - Memcheck:Leak - fun:memalign - fun:posix_memalign - fun:ngx_memalign - fun:ngx_palloc_block - fun:ngx_palloc -} { Memcheck:Addr8 @@ -213,3 +114,22 @@ fun:ngx_http_lua_get_output_header 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 +} From 8acbe3fbc400848abfa345e8db5ffe1bebc9c0bb Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:22:39 +0200 Subject: [PATCH 046/414] http-echo: Upgrade to 0.61 Drop build-nginx-1.11.11 patch now included upstream --- debian/modules/control | 3 +- debian/modules/http-echo/README.markdown | 24 +- .../http-echo/src/ngx_http_echo_module.c | 13 ++ .../http-echo/src/ngx_http_echo_module.h | 4 + .../src/ngx_http_echo_request_info.c | 62 +++++ .../src/ngx_http_echo_request_info.h | 3 + debian/modules/http-echo/valgrind.suppress | 10 + .../http-echo/build-nginx-1.11.11.patch | 212 ------------------ debian/modules/patches/http-echo/series | 1 - 9 files changed, 107 insertions(+), 225 deletions(-) delete mode 100644 debian/modules/patches/http-echo/build-nginx-1.11.11.patch delete mode 100644 debian/modules/patches/http-echo/series diff --git a/debian/modules/control b/debian/modules/control index 71c63eb..b779595 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -13,9 +13,8 @@ Version: v1.5.1 Module: http-echo Homepage: https://github.com/agentzh/echo-nginx-module -Version: v0.60 +Version: v0.61 Files-Excluded: .gitignore .gitattributes .travis.yml -Patch: build-nginx-1.11.11.patch Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module diff --git a/debian/modules/http-echo/README.markdown b/debian/modules/http-echo/README.markdown index 9de2c0b..71ac080 100644 --- a/debian/modules/http-echo/README.markdown +++ b/debian/modules/http-echo/README.markdown @@ -68,7 +68,7 @@ This module is production ready. Version ======= -This document describes ngx_echo [v0.59](https://github.com/openresty/echo-nginx-module/tags) released on 15 May 2016. +This document describes ngx_echo [v0.61](https://github.com/openresty/echo-nginx-module/tags) released on 8 August 2017. Synopsis ======== @@ -284,9 +284,9 @@ People will also find it useful in real-world applications that need to 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. -Technially, this module has also demonstrated the following techniques that might be helpful for module writers: +Technically, this module has also demonstrated the following techniques that might be helpful for module writers: -1. Issue parallel subreqeusts directly from content handler. +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. @@ -395,7 +395,7 @@ The output on the client side looks like this 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 esacpe this characters. (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.) +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 @@ -1493,6 +1493,8 @@ Accessing `/echoback` yields 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) @@ -1569,13 +1571,13 @@ You're recommended to install this module (as well as the Nginx core and many ot 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.9.15 (see [nginx compatibility](#compatibility)), and then build the source with this module: +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.9.15.tar.gz' - $ tar -xzvf nginx-1.9.15.tar.gz - $ cd nginx-1.9.15/ + $ 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 \ @@ -1604,6 +1606,8 @@ Compatibility The following versions of Nginx should work with this module: +* **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) @@ -1796,7 +1800,7 @@ You'll be very welcomed to submit patches to the [author](#author) or just ask f Author ====== -Yichun "agentzh" Zhang (章亦春) *<agentzh@gmail.com>*, CloudFlare Inc. +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. @@ -1805,7 +1809,7 @@ This wiki page is also maintained by the author himself, and everybody is encour Copyright & License =================== -Copyright (c) 2009-2016, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. +Copyright (c) 2009-2017, Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. This module is licensed under the terms of the BSD license. diff --git a/debian/modules/http-echo/src/ngx_http_echo_module.c b/debian/modules/http-echo/src/ngx_http_echo_module.c index ae70479..8d736d7 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_module.c +++ b/debian/modules/http-echo/src/ngx_http_echo_module.c @@ -632,6 +632,9 @@ ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *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)); @@ -643,6 +646,16 @@ ngx_http_echo_create_main_conf(ngx_conf_t *cf) * 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; } diff --git a/debian/modules/http-echo/src/ngx_http_echo_module.h b/debian/modules/http-echo/src/ngx_http_echo_module.h index 2d212c3..ce0a305 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_module.h +++ b/debian/modules/http-echo/src/ngx_http_echo_module.h @@ -92,6 +92,10 @@ typedef struct { 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; diff --git a/debian/modules/http-echo/src/ngx_http_echo_request_info.c b/debian/modules/http-echo/src/ngx_http_echo_request_info.c index d28ec4d..7dd3683 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_request_info.c +++ b/debian/modules/http-echo/src/ngx_http_echo_request_info.c @@ -17,6 +17,9 @@ 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 @@ -179,6 +182,11 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, 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; @@ -195,6 +203,10 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, } #endif +#if nginx_version >= 1011011 + emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module); +#endif + size = 0; b = c->buffer; @@ -215,8 +227,35 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, 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 @@ -280,8 +319,15 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, } 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) { @@ -457,4 +503,20 @@ ngx_http_echo_response_status_variable(ngx_http_request_t *r, 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/debian/modules/http-echo/src/ngx_http_echo_request_info.h b/debian/modules/http-echo/src/ngx_http_echo_request_info.h index 3b3713b..aa5730b 100644 --- a/debian/modules/http-echo/src/ngx_http_echo_request_info.h +++ b/debian/modules/http-echo/src/ngx_http_echo_request_info.h @@ -29,5 +29,8 @@ ngx_int_t ngx_http_echo_request_uri_variable(ngx_http_request_t *r, 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/debian/modules/http-echo/valgrind.suppress b/debian/modules/http-echo/valgrind.suppress index 0f8e871..d4bfe63 100644 --- a/debian/modules/http-echo/valgrind.suppress +++ b/debian/modules/http-echo/valgrind.suppress @@ -36,3 +36,13 @@ 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 +} diff --git a/debian/modules/patches/http-echo/build-nginx-1.11.11.patch b/debian/modules/patches/http-echo/build-nginx-1.11.11.patch deleted file mode 100644 index dbb9ce7..0000000 --- a/debian/modules/patches/http-echo/build-nginx-1.11.11.patch +++ /dev/null @@ -1,212 +0,0 @@ -From 7740e11558b530b66b469c657576f5280b7cdb1b Mon Sep 17 00:00:00 2001 -From: Andrei Belov -Date: Wed, 22 Mar 2017 08:43:30 +0300 -Subject: [PATCH] feature: nginx 1.11.11+ can now build with this module. - -Note: nginx 1.11.11+ are still not an officially supported target yet. -More work needed. - -Closes openresty/echo-nginx-module#64 - -See also: -http://hg.nginx.org/nginx/rev/e662cbf1b932 - -Signed-off-by: Yichun Zhang (agentzh) ---- - src/ngx_http_echo_module.c | 13 +++++++++ - src/ngx_http_echo_module.h | 4 +++ - src/ngx_http_echo_request_info.c | 62 ++++++++++++++++++++++++++++++++++++++++ - src/ngx_http_echo_request_info.h | 3 ++ - valgrind.suppress | 10 +++++++ - 5 files changed, 92 insertions(+) - -diff --git a/src/ngx_http_echo_module.c b/src/ngx_http_echo_module.c -index ae70479..8d736d7 100644 ---- a/src/ngx_http_echo_module.c -+++ b/src/ngx_http_echo_module.c -@@ -632,6 +632,9 @@ ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *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)); -@@ -643,6 +646,16 @@ ngx_http_echo_create_main_conf(ngx_conf_t *cf) - * 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; - } - -diff --git a/src/ngx_http_echo_module.h b/src/ngx_http_echo_module.h -index 2d212c3..ce0a305 100644 ---- a/src/ngx_http_echo_module.h -+++ b/src/ngx_http_echo_module.h -@@ -92,6 +92,10 @@ typedef struct { - - 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; - - -diff --git a/src/ngx_http_echo_request_info.c b/src/ngx_http_echo_request_info.c -index d28ec4d..7dd3683 100644 ---- a/src/ngx_http_echo_request_info.c -+++ b/src/ngx_http_echo_request_info.c -@@ -17,6 +17,9 @@ - - - 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 -@@ -179,6 +182,11 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - 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; -@@ -195,6 +203,10 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - } - #endif - -+#if nginx_version >= 1011011 -+ emcf = ngx_http_get_module_main_conf(r, ngx_http_echo_module); -+#endif -+ - size = 0; - b = c->buffer; - -@@ -215,8 +227,35 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - - 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 -@@ -280,8 +319,15 @@ ngx_http_echo_client_request_headers_variable(ngx_http_request_t *r, - } - - 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) { -@@ -457,4 +503,20 @@ ngx_http_echo_response_status_variable(ngx_http_request_t *r, - 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/src/ngx_http_echo_request_info.h b/src/ngx_http_echo_request_info.h -index 3b3713b..aa5730b 100644 ---- a/src/ngx_http_echo_request_info.h -+++ b/src/ngx_http_echo_request_info.h -@@ -29,5 +29,8 @@ ngx_int_t ngx_http_echo_request_uri_variable(ngx_http_request_t *r, - 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/valgrind.suppress b/valgrind.suppress -index 0f8e871..d4bfe63 100644 ---- a/valgrind.suppress -+++ b/valgrind.suppress -@@ -36,3 +36,13 @@ - 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 -+} --- -2.11.0 - diff --git a/debian/modules/patches/http-echo/series b/debian/modules/patches/http-echo/series deleted file mode 100644 index 7e5c302..0000000 --- a/debian/modules/patches/http-echo/series +++ /dev/null @@ -1 +0,0 @@ -build-nginx-1.11.11.patch From 5fb0700fb278a7a8217233755c6e688ffc8e5e94 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:22:50 +0200 Subject: [PATCH 047/414] http-lua: Upgrade to 0.10.11 Rebase openssl-1.1.0 patch --- debian/modules/control | 2 +- debian/modules/http-lua/README.markdown | 182 +++++++++++++++++- .../modules/http-lua/doc/HttpLuaModule.wiki | 162 +++++++++++++++- .../http-lua/src/api/ngx_http_lua_api.h | 2 +- .../http-lua/src/ngx_http_lua_accessby.c | 10 +- .../http-lua/src/ngx_http_lua_directive.c | 2 +- .../http-lua/src/ngx_http_lua_output.c | 7 +- .../http-lua/src/ngx_http_lua_req_body.c | 6 +- .../http-lua/src/ngx_http_lua_rewriteby.c | 10 +- .../http-lua/src/ngx_http_lua_semaphore.c | 6 +- .../http-lua/src/ngx_http_lua_shdict.c | 167 ++++++++++++++++ .../modules/http-lua/src/ngx_http_lua_sleep.c | 6 +- .../http-lua/src/ngx_http_lua_socket_tcp.c | 25 ++- .../http-lua/src/ngx_http_lua_socket_udp.c | 6 +- .../http-lua/src/ngx_http_lua_ssl_certby.c | 5 +- .../src/ngx_http_lua_ssl_session_fetchby.c | 5 +- .../src/ngx_http_lua_ssl_session_storeby.c | 3 +- .../http-lua/src/ngx_http_lua_subrequest.c | 6 +- .../modules/http-lua/src/ngx_http_lua_util.c | 10 +- .../modules/http-lua/src/ngx_http_lua_util.h | 2 +- debian/modules/http-lua/t/000--init.t | 73 ++++--- debian/modules/http-lua/t/002-content.t | 8 +- debian/modules/http-lua/t/004-require.t | 1 + debian/modules/http-lua/t/017-exec.t | 24 ++- debian/modules/http-lua/t/023-rewrite/exec.t | 24 ++- .../t/023-rewrite/tcp-socket-timeout.t | 44 ++--- debian/modules/http-lua/t/024-access/exec.t | 24 ++- debian/modules/http-lua/t/035-gmatch.t | 1 + debian/modules/http-lua/t/058-tcp-socket.t | 39 +++- .../http-lua/t/065-tcp-socket-timeout.t | 68 ++++--- .../modules/http-lua/t/097-uthread-rewrite.t | 1 + debian/modules/http-lua/t/106-timer.t | 6 +- debian/modules/http-lua/t/129-ssl-socket.t | 6 +- debian/modules/http-lua/t/139-ssl-cert-by.t | 8 +- .../http-lua/t/142-ssl-session-store.t | 7 +- .../http-lua/t/143-ssl-session-fetch.t | 19 +- .../http-lua/t/147-tcp-socket-timeouts.t | 93 +++++++++ debian/modules/http-lua/t/154-semaphore.t | 2 + debian/modules/http-lua/util/build.sh | 4 + debian/modules/http-lua/valgrind.suppress | 68 +++++-- .../patches/http-lua/openssl-1.1.0.patch | 86 ++++----- 41 files changed, 1007 insertions(+), 223 deletions(-) diff --git a/debian/modules/control b/debian/modules/control index b779595..bd7cc0a 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -18,7 +18,7 @@ Files-Excluded: .gitignore .gitattributes .travis.yml Module: http-lua Homepage: https://github.com/openresty/lua-nginx-module -Version: v0.10.10 +Version: v0.10.11 Patch: openssl-1.1.0.patch discover-luajit-2.1.patch diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown index fac3a0d..c42bd3e 100644 --- a/debian/modules/http-lua/README.markdown +++ b/debian/modules/http-lua/README.markdown @@ -62,7 +62,7 @@ Production ready. Version ======= -This document describes ngx_lua [v0.10.10](https://github.com/openresty/lua-nginx-module/tags) released on 8 August 2017. +This document describes ngx_lua [v0.10.11](https://github.com/openresty/lua-nginx-module/tags) released on 3 November 2017. Synopsis ======== @@ -249,6 +249,7 @@ Nginx Compatibility The latest version of this module is compatible with the following versions of Nginx: +* 1.13.x (last tested: 1.13.6) * 1.11.x (last tested: 1.11.2) * 1.10.x * 1.9.x (last tested: 1.9.15) @@ -276,9 +277,9 @@ 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/ + wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' + tar -xzvf nginx-1.13.6.tar.gz + cd nginx-1.13.6/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -871,6 +872,7 @@ Nginx may terminate a request early with (at least): * 400 (Bad Request) * 405 (Not Allowed) * 408 (Request Timeout) +* 413 (Request Entity Too Large) * 414 (Request URI Too Large) * 494 (Request Headers Too Large) * 499 (Client Closed Request) @@ -1335,16 +1337,19 @@ Runs the Lua code specified by the argument `` on the global Lua When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. In case that the [lua_code_cache](#lua_code_cache) directive is turned off (default on), the `init_by_lua` handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. -Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: +Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: ```nginx - init_by_lua 'cjson = require "cjson"'; + # this runs before forking out nginx worker processes: + init_by_lua_block { require "cjson" } server { location = /api { content_by_lua_block { - ngx.say(cjson.encode({dog = 5, cat = 6})) + -- the following require() will just return + -- the alrady loaded module from package.loaded: + ngx.say(require "cjson".encode{dog = 5, cat = 6}) } } } @@ -1356,10 +1361,10 @@ You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at t lua_shared_dict dogs 1m; - init_by_lua ' + init_by_lua_block { local dogs = ngx.shared.dogs; dogs:set("Tom", 56) - '; + } server { location = /api { @@ -2691,7 +2696,7 @@ ssl_session_store_by_lua_file **context:** *http* -**phase:** *right-before-SSL-handshake* +**phase:** *right-after-SSL-handshake* Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. @@ -3188,9 +3193,13 @@ Nginx API for Lua * [ngx.shared.DICT.lpop](#ngxshareddictlpop) * [ngx.shared.DICT.rpop](#ngxshareddictrpop) * [ngx.shared.DICT.llen](#ngxshareddictllen) +* [ngx.shared.DICT.ttl](#ngxshareddictttl) +* [ngx.shared.DICT.expire](#ngxshareddictexpire) * [ngx.shared.DICT.flush_all](#ngxshareddictflush_all) * [ngx.shared.DICT.flush_expired](#ngxshareddictflush_expired) * [ngx.shared.DICT.get_keys](#ngxshareddictget_keys) +* [ngx.shared.DICT.capacity](#ngxshareddictcapacity) +* [ngx.shared.DICT.free_space](#ngxshareddictfree_space) * [ngx.socket.udp](#ngxsocketudp) * [udpsock:setpeername](#udpsocksetpeername) * [udpsock:send](#udpsocksend) @@ -6195,9 +6204,13 @@ The resulting object `dict` has the following methods: * [lpop](#ngxshareddictlpop) * [rpop](#ngxshareddictrpop) * [llen](#ngxshareddictllen) +* [ttl](#ngxshareddictttl) +* [expire](#ngxshareddictexpire) * [flush_all](#ngxshareddictflush_all) * [flush_expired](#ngxshareddictflush_expired) * [get_keys](#ngxshareddictget_keys) +* [capacity](#ngxshareddictcapacity) +* [free_space](#ngxshareddictfree_space) All these methods are *atomic* operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same `lua_shared_dict` zone. @@ -6540,6 +6553,82 @@ See also [ngx.shared.DICT](#ngxshareddict). [Back to TOC](#nginx-api-for-lua) +ngx.shared.DICT.ttl +------------------- +**syntax:** *ttl, err = ngx.shared.DICT:ttl(key)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Retrieves the remaining TTL (time-to-live in seconds) of a key-value pair in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns the TTL as a number if the operation is successfully completed or `nil` and an error message otherwise. + +If the key does not exist (or has already expired), this method will return `nil` and the error string `"not found"`. + +The TTL is originally determined by the `exptime` argument of the [set](#ngxshareddictset), [add](#ngxshareddictadd), [replace](#ngxshareddictreplace) (and the likes) methods. It has a time resolution of `0.001` seconds. A value of `0` means that the item will never expire. + +Example: + +```lua + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.5) + + ngx.sleep(0.2) + + local ttl, err = cats:ttl("Marry") + ngx.say(ttl) -- 0.3 +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.expire +---------------------- +**syntax:** *success, err = ngx.shared.DICT:expire(key, exptime)* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Updates the `exptime` (in second) of a key-value pair in the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). Returns a boolean indicating success if the operation completes or `nil` and an error message otherwise. + +If the key does not exist, this method will return `nil` and the error string `"not found"`. + +The `exptime` argument has a resolution of `0.001` seconds. If `exptime` is `0`, then the item will never expire. + +Example: + +```lua + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.1) + + succ, err = cats:expire("Marry", 0.5) + + ngx.sleep(0.2) + + local val, err = cats:get("Marry") + ngx.say(val) -- "a nice cat" +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + ngx.shared.DICT.flush_all ------------------------- **syntax:** *ngx.shared.DICT:flush_all()* @@ -6586,6 +6675,79 @@ This feature was first introduced in the `v0.7.3` release. [Back to TOC](#nginx-api-for-lua) +ngx.shared.DICT.capacity +------------------------ +**syntax:** *capacity_bytes = ngx.shared.DICT:capacity()* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Retrieves the capacity in bytes for the shm-based dictionary [ngx.shared.DICT](#ngxshareddict) declared with +the [lua_shared_dict](#lua_shared_dict) directive. + +Example: + +```lua + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local capacity_bytes = cats:capacity() +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +This feature requires at least nginx core version `0.7.3`. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + +ngx.shared.DICT.free_space +-------------------------- +**syntax:** *free_page_bytes = ngx.shared.DICT:free_space()* + +**context:** *init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua** + +**requires:** `resty.core.shdict` or `resty.core` + +Retrieves the free page size in bytes for the shm-based dictionary [ngx.shared.DICT](#ngxshareddict). + +**Note:** The memory for ngx.shared.DICT is allocated via the nginx slab allocator which has each slot for +data size ranges like \~8, 9\~16, 17\~32, ..., 1025\~2048, 2048\~ bytes. And pages are assigned to a slot if there +is no room in already assigned pages for the slot. + +So even if the return value of the `free_space` method is zero, there may be room in already assigned pages, so +you may successfully set a new key value pair to the shared dict without getting `true` for `forcible` or +non nil `err` from the `ngx.shared.DICT.set`. + +On the other hand, if already assigned pages for a slot are full and a new key value pair is added to the +slot and there is no free page, you may get `true` for `forcible` or non nil `err` from the +`ngx.shared.DICT.set` method. + +Example: + +```lua + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local free_page_bytes = cats:free_space() +``` + +This feature was first introduced in the `v0.10.11` release. + +**Note:** This method requires the `resty.core.shdict` or `resty.core` modules from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. + +This feature requires at least nginx core version `1.11.7`. + +See also [ngx.shared.DICT](#ngxshareddict). + +[Back to TOC](#nginx-api-for-lua) + ngx.socket.udp -------------- **syntax:** *udpsock = ngx.socket.udp()* diff --git a/debian/modules/http-lua/doc/HttpLuaModule.wiki b/debian/modules/http-lua/doc/HttpLuaModule.wiki index 8393056..2424d39 100644 --- a/debian/modules/http-lua/doc/HttpLuaModule.wiki +++ b/debian/modules/http-lua/doc/HttpLuaModule.wiki @@ -10,7 +10,7 @@ Production ready. = Version = -This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.10] released on 8 August 2017. +This document describes ngx_lua [https://github.com/openresty/lua-nginx-module/tags v0.10.11] released on 3 November 2017. = Synopsis = @@ -186,6 +186,7 @@ The Lua state (Lua VM instance) is shared across all the requests handled by a s The latest version of this module is compatible with the following versions of Nginx: +* 1.13.x (last tested: 1.13.6) * 1.11.x (last tested: 1.11.2) * 1.10.x * 1.9.x (last tested: 1.9.15) @@ -209,9 +210,9 @@ Alternatively, ngx_lua can be manually compiled into Nginx: Build the source with this module: - wget 'http://nginx.org/download/nginx-1.11.2.tar.gz' - tar -xzvf nginx-1.11.2.tar.gz - cd nginx-1.11.2/ + wget 'http://nginx.org/download/nginx-1.13.6.tar.gz' + tar -xzvf nginx-1.13.6.tar.gz + cd nginx-1.13.6/ # tell nginx's build system where to find LuaJIT 2.0: export LUAJIT_LIB=/path/to/luajit/lib @@ -706,6 +707,7 @@ Nginx may terminate a request early with (at least): * 400 (Bad Request) * 405 (Not Allowed) * 408 (Request Timeout) +* 413 (Request Entity Too Large) * 414 (Request URI Too Large) * 494 (Request Headers Too Large) * 499 (Client Closed Request) @@ -1057,15 +1059,18 @@ Runs the Lua code specified by the argument on the When Nginx receives the HUP signal and starts reloading the config file, the Lua VM will also be re-created and init_by_lua will run again on the new Lua VM. In case that the [[#lua_code_cache|lua_code_cache]] directive is turned off (default on), the init_by_lua handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. -Usually you can register (true) Lua global variables or pre-load Lua modules at server start-up by means of this hook. Here is an example for pre-loading Lua modules: +Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: - init_by_lua 'cjson = require "cjson"'; + # this runs before forking out nginx worker processes: + init_by_lua_block { require "cjson" } server { location = /api { content_by_lua_block { - ngx.say(cjson.encode({dog = 5, cat = 6})) + -- the following require() will just return + -- the alrady loaded module from package.loaded: + ngx.say(require "cjson".encode{dog = 5, cat = 6}) } } } @@ -1076,10 +1081,10 @@ You can also initialize the [[#lua_shared_dict|lua_shared_dict]] shm storage at lua_shared_dict dogs 1m; - init_by_lua ' + init_by_lua_block { local dogs = ngx.shared.dogs; dogs:set("Tom", 56) - '; + } server { location = /api { @@ -2276,7 +2281,7 @@ Note that: this directive is only allowed to used in '''http context''' from the '''context:''' ''http'' -'''phase:''' ''right-before-SSL-handshake'' +'''phase:''' ''right-after-SSL-handshake'' Equivalent to [[#ssl_session_store_by_lua_block|ssl_session_store_by_lua_block]], except that the file specified by contains the Lua code, or rather, the [[#Lua/LuaJIT bytecode support|Lua/LuaJIT bytecode]] to be executed. @@ -5193,9 +5198,13 @@ The resulting object dict has the following methods: * [[#ngx.shared.DICT.lpop|lpop]] * [[#ngx.shared.DICT.rpop|rpop]] * [[#ngx.shared.DICT.llen|llen]] +* [[#ngx.shared.DICT.ttl|ttl]] +* [[#ngx.shared.DICT.expire|expire]] * [[#ngx.shared.DICT.flush_all|flush_all]] * [[#ngx.shared.DICT.flush_expired|flush_expired]] * [[#ngx.shared.DICT.get_keys|get_keys]] +* [[#ngx.shared.DICT.capacity|capacity]] +* [[#ngx.shared.DICT.free_space|free_space]] All these methods are ''atomic'' operations, that is, safe from concurrent accesses from multiple nginx worker processes for the same lua_shared_dict zone. @@ -5488,6 +5497,74 @@ This feature was first introduced in the v0.10.6 release. See also [[#ngx.shared.DICT|ngx.shared.DICT]]. +== ngx.shared.DICT.ttl == +'''syntax:''' ''ttl, err = ngx.shared.DICT:ttl(key)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Retrieves the remaining TTL (time-to-live in seconds) of a key-value pair in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns the TTL as a number if the operation is successfully completed or nil and an error message otherwise. + +If the key does not exist (or has already expired), this method will return nil and the error string "not found". + +The TTL is originally determined by the exptime argument of the [[#ngx.shared.DICT.set|set]], [[#ngx.shared.DICT.add|add]], [[#ngx.shared.DICT.replace|replace]] (and the likes) methods. It has a time resolution of 0.001 seconds. A value of 0 means that the item will never expire. + +Example: + + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.5) + + ngx.sleep(0.2) + + local ttl, err = cats:ttl("Marry") + ngx.say(ttl) -- 0.3 + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.expire == +'''syntax:''' ''success, err = ngx.shared.DICT:expire(key, exptime)'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Updates the exptime (in second) of a key-value pair in the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. Returns a boolean indicating success if the operation completes or nil and an error message otherwise. + +If the key does not exist, this method will return nil and the error string "not found". + +The exptime argument has a resolution of 0.001 seconds. If exptime is 0, then the item will never expire. + +Example: + + + require "resty.core" + + local cats = ngx.shared.cats + local succ, err = cats:set("Marry", "a nice cat", 0.1) + + succ, err = cats:expire("Marry", 0.5) + + ngx.sleep(0.2) + + local val, err = cats:get("Marry") + ngx.say(val) -- "a nice cat" + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.shared.DICT.flush_all == '''syntax:''' ''ngx.shared.DICT:flush_all()'' @@ -5525,6 +5602,71 @@ By default, only the first 1024 keys (if any) are returned. When the v0.7.3 release. +== ngx.shared.DICT.capacity == +'''syntax:''' ''capacity_bytes = ngx.shared.DICT:capacity()'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Retrieves the capacity in bytes for the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]] declared with +the [[#lua_shared_dict|lua_shared_dict]] directive. + +Example: + + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local capacity_bytes = cats:capacity() + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +This feature requires at least nginx core version 0.7.3. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + +== ngx.shared.DICT.free_space == +'''syntax:''' ''free_page_bytes = ngx.shared.DICT:free_space()'' + +'''context:''' ''init_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*'' + +'''requires:''' resty.core.shdict or resty.core + +Retrieves the free page size in bytes for the shm-based dictionary [[#ngx.shared.DICT|ngx.shared.DICT]]. + +'''Note:''' The memory for ngx.shared.DICT is allocated via the nginx slab allocator which has each slot for +data size ranges like \~8, 9\~16, 17\~32, ..., 1025\~2048, 2048\~ bytes. And pages are assigned to a slot if there +is no room in already assigned pages for the slot. + +So even if the return value of the free_space method is zero, there may be room in already assigned pages, so +you may successfully set a new key value pair to the shared dict without getting true for forcible or +non nil err from the ngx.shared.DICT.set. + +On the other hand, if already assigned pages for a slot are full and a new key value pair is added to the +slot and there is no free page, you may get true for forcible or non nil err from the +ngx.shared.DICT.set method. + +Example: + + + require "resty.core.shdict" + + local cats = ngx.shared.cats + local free_page_bytes = cats:free_space() + + +This feature was first introduced in the v0.10.11 release. + +'''Note:''' This method requires the resty.core.shdict or resty.core modules from the [https://github.com/openresty/lua-resty-core lua-resty-core] library. + +This feature requires at least nginx core version 1.11.7. + +See also [[#ngx.shared.DICT|ngx.shared.DICT]]. + == ngx.socket.udp == '''syntax:''' ''udpsock = ngx.socket.udp()'' diff --git a/debian/modules/http-lua/src/api/ngx_http_lua_api.h b/debian/modules/http-lua/src/api/ngx_http_lua_api.h index cd64fc8..1e07b71 100644 --- a/debian/modules/http-lua/src/api/ngx_http_lua_api.h +++ b/debian/modules/http-lua/src/api/ngx_http_lua_api.h @@ -19,7 +19,7 @@ /* Public API for other Nginx modules */ -#define ngx_http_lua_version 10010 +#define ngx_http_lua_version 10011 typedef struct { diff --git a/debian/modules/http-lua/src/ngx_http_lua_accessby.c b/debian/modules/http-lua/src/ngx_http_lua_accessby.c index 1a4ba6d..56bf0fa 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_accessby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_accessby.c @@ -238,6 +238,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) { int co_ref; ngx_int_t rc; + ngx_uint_t nreqs; lua_State *co; ngx_event_t *rev; ngx_connection_t *c; @@ -329,6 +330,9 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) r->read_event_handler = ngx_http_block_reading; } + c = r->connection; + nreqs = c->requests; + rc = ngx_http_lua_run_thread(L, r, ctx, 0); dd("returned %d", (int) rc); @@ -337,10 +341,8 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) return rc; } - c = r->connection; - if (rc == NGX_AGAIN) { - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; @@ -353,7 +355,7 @@ ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r) } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) { return rc; diff --git a/debian/modules/http-lua/src/ngx_http_lua_directive.c b/debian/modules/http-lua/src/ngx_http_lua_directive.c index 6a562f4..014a472 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_directive.c +++ b/debian/modules/http-lua/src/ngx_http_lua_directive.c @@ -1542,7 +1542,7 @@ ngx_http_lua_conf_read_lua_token(ngx_conf_t *cf, #if nginx_version >= 1009002 if (dump) { - dump->last = ngx_cpymem(dump->last, b->pos, size); + dump->last = ngx_cpymem(dump->last, b->start + len, size); } #endif } diff --git a/debian/modules/http-lua/src/ngx_http_lua_output.c b/debian/modules/http-lua/src/ngx_http_lua_output.c index b410ba4..0fe8840 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_output.c +++ b/debian/modules/http-lua/src/ngx_http_lua_output.c @@ -724,6 +724,7 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) int n; lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; c = r->connection; @@ -748,18 +749,20 @@ ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) } vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; + rc = ngx_http_lua_run_thread(vm, r, ctx, n); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } /* rc == NGX_ERROR || rc >= NGX_OK */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_req_body.c b/debian/modules/http-lua/src/ngx_http_lua_req_body.c index 6f2ae38..e6bf3c1 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_req_body.c +++ b/debian/modules/http-lua/src/ngx_http_lua_req_body.c @@ -1125,6 +1125,7 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) { lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; @@ -1134,6 +1135,7 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, 0); @@ -1141,12 +1143,12 @@ ngx_http_lua_read_body_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c index 44d8941..077c2d3 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_rewriteby.c @@ -235,6 +235,7 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) int co_ref; lua_State *co; ngx_int_t rc; + ngx_uint_t nreqs; ngx_event_t *rev; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; @@ -324,20 +325,21 @@ ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r) r->read_event_handler = ngx_http_block_reading; } + c = r->connection; + nreqs = c->requests; + rc = ngx_http_lua_run_thread(L, r, ctx, 0); if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } - c = r->connection; - if (rc == NGX_AGAIN) { - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); } else if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - rc = ngx_http_lua_run_posted_threads(c, L, r, ctx); + rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs); } if (rc == NGX_OK || rc == NGX_DECLINED) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_semaphore.c b/debian/modules/http-lua/src/ngx_http_lua_semaphore.c index eda0141..0b70aea 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_semaphore.c +++ b/debian/modules/http-lua/src/ngx_http_lua_semaphore.c @@ -258,6 +258,7 @@ ngx_http_lua_sema_resume(ngx_http_request_t *r) lua_State *vm; ngx_connection_t *c; ngx_int_t rc; + ngx_uint_t nreqs; ngx_http_lua_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -269,6 +270,7 @@ ngx_http_lua_sema_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; if (ctx->cur_co_ctx->sem_resume_status == SEMAPHORE_WAIT_SUCC) { lua_pushboolean(ctx->cur_co_ctx->co, 1); @@ -285,12 +287,12 @@ ngx_http_lua_sema_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } /* rc == NGX_ERROR || rc >= NGX_OK */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_shdict.c b/debian/modules/http-lua/src/ngx_http_lua_shdict.c index d6cad7e..5b48eb4 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_shdict.c +++ b/debian/modules/http-lua/src/ngx_http_lua_shdict.c @@ -2843,6 +2843,173 @@ ngx_http_lua_ffi_shdict_flush_all(ngx_shm_zone_t *zone) return NGX_OK; } + + +static ngx_int_t +ngx_http_lua_shdict_peek(ngx_shm_zone_t *shm_zone, ngx_uint_t hash, + u_char *kdata, size_t klen, ngx_http_lua_shdict_node_t **sdp) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + ctx = shm_zone->data; + + node = ctx->sh->rbtree.root; + sentinel = ctx->sh->rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + sd = (ngx_http_lua_shdict_node_t *) &node->color; + + rc = ngx_memn2cmp(kdata, sd->data, klen, (size_t) sd->key_len); + + if (rc == 0) { + *sdp = sd; + + return NGX_OK; + } + + node = (rc < 0) ? node->left : node->right; + } + + *sdp = NULL; + + return NGX_DECLINED; +} + + +int +ngx_http_lua_ffi_shdict_get_ttl(ngx_shm_zone_t *zone, u_char *key, + size_t key_len) +{ + uint32_t hash; + uint64_t now; + uint64_t expires; + ngx_int_t rc; + ngx_time_t *tp; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + if (zone == NULL) { + return NGX_ERROR; + } + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); + + if (rc == NGX_DECLINED) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + expires = sd->expires; + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + if (expires == 0) { + return 0; + } + + tp = ngx_timeofday(); + now = (uint64_t) tp->sec * 1000 + tp->msec; + + return expires - now; +} + + +int +ngx_http_lua_ffi_shdict_set_expire(ngx_shm_zone_t *zone, u_char *key, + size_t key_len, int exptime) +{ + uint32_t hash; + ngx_int_t rc; + ngx_time_t *tp = NULL; + ngx_http_lua_shdict_ctx_t *ctx; + ngx_http_lua_shdict_node_t *sd; + + if (zone == NULL) { + return NGX_ERROR; + } + + if (exptime > 0) { + tp = ngx_timeofday(); + } + + ctx = zone->data; + hash = ngx_crc32_short(key, key_len); + + ngx_shmtx_lock(&ctx->shpool->mutex); + + rc = ngx_http_lua_shdict_peek(zone, hash, key, key_len, &sd); + + if (rc == NGX_DECLINED) { + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_DECLINED; + } + + /* rc == NGX_OK */ + + if (exptime > 0) { + sd->expires = (uint64_t) tp->sec * 1000 + tp->msec + + (uint64_t) exptime; + + } else { + sd->expires = 0; + } + + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return NGX_OK; +} + + +size_t +ngx_http_lua_ffi_shdict_capacity(ngx_shm_zone_t *zone) +{ + return zone->shm.size; +} + + +# if nginx_version >= 1011007 +size_t +ngx_http_lua_ffi_shdict_free_space(ngx_shm_zone_t *zone) +{ + size_t bytes; + ngx_http_lua_shdict_ctx_t *ctx; + + ctx = zone->data; + + ngx_shmtx_lock(&ctx->shpool->mutex); + bytes = ctx->shpool->pfree * ngx_pagesize; + ngx_shmtx_unlock(&ctx->shpool->mutex); + + return bytes; +} +# endif /* nginx_version >= 1011007 */ + + #endif /* NGX_LUA_NO_FFI_API */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_sleep.c b/debian/modules/http-lua/src/ngx_http_lua_sleep.c index ffee97f..09ea0f6 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_sleep.c +++ b/debian/modules/http-lua/src/ngx_http_lua_sleep.c @@ -180,6 +180,7 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) lua_State *vm; ngx_connection_t *c; ngx_int_t rc; + ngx_uint_t nreqs; ngx_http_lua_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); @@ -191,6 +192,7 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, 0); @@ -198,12 +200,12 @@ ngx_http_lua_sleep_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c index 382a94d..f0988bc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c @@ -474,6 +474,7 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) switch (lua_type(L, -1)) { case LUA_TNUMBER: lua_tostring(L, -1); + /* FALLTHROUGH */ case LUA_TSTRING: custom_pool = 1; @@ -743,6 +744,9 @@ ngx_http_lua_socket_tcp_connect(lua_State *L) u->ft_type |= NGX_HTTP_LUA_SOCKET_FT_RESOLVER; + coctx->cleanup = NULL; + coctx->data = NULL; + u->resolved->ctx = NULL; lua_pushnil(L); lua_pushfstring(L, "%s could not be resolved", host.data); @@ -2708,6 +2712,10 @@ ngx_http_lua_socket_tcp_settimeout(lua_State *L) } timeout = (ngx_int_t) lua_tonumber(L, 2); + if (timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } + lua_pushinteger(L, timeout); lua_pushinteger(L, timeout); @@ -2751,8 +2759,19 @@ ngx_http_lua_socket_tcp_settimeouts(lua_State *L) } connect_timeout = (ngx_int_t) lua_tonumber(L, 2); + if (connect_timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } + send_timeout = (ngx_int_t) lua_tonumber(L, 3); + if (send_timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } + read_timeout = (ngx_int_t) lua_tonumber(L, 4); + if (read_timeout >> 31) { + return luaL_error(L, "bad timeout value"); + } lua_rawseti(L, 1, SOCKET_READ_TIMEOUT_INDEX); lua_rawseti(L, 1, SOCKET_SEND_TIMEOUT_INDEX); @@ -5234,6 +5253,7 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) int nret; lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; @@ -5284,6 +5304,7 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, nret); @@ -5291,12 +5312,12 @@ ngx_http_lua_socket_tcp_resume_helper(ngx_http_request_t *r, int socket_op) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c index 1ec0c00..08ba1cc 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c +++ b/debian/modules/http-lua/src/ngx_http_lua_socket_udp.c @@ -1514,6 +1514,7 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) int nret; lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; @@ -1549,6 +1550,7 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, nret); @@ -1556,12 +1558,12 @@ ngx_http_lua_socket_udp_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c index c3591d1..95be47f 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c @@ -197,7 +197,8 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) c = ngx_ssl_get_connection(ssl_conn); - dd("c = %p", c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl cert: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); @@ -220,6 +221,8 @@ ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data) dd("first time"); + ngx_reusable_connection(c, 0); + hc = c->data; fc = ngx_http_lua_create_fake_connection(NULL); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c index 556b732..3a3c1f5 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c @@ -191,7 +191,8 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, c = ngx_ssl_get_connection(ssl_conn); - dd("c = %p", c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session fetch: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); @@ -224,6 +225,8 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, dd("first time"); + ngx_reusable_connection(c, 0); + hc = c->data; fc = ngx_http_lua_create_fake_connection(NULL); diff --git a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c index bae8273..f83e85d 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c +++ b/debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c @@ -183,7 +183,8 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, c = ngx_ssl_get_connection(ssl_conn); - dd("c = %p", c); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "ssl session store: connection reusable: %ud", c->reusable); cctx = ngx_http_lua_ssl_get_ctx(c->ssl->connection); diff --git a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c index 6f7aa97..47096e9 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_subrequest.c +++ b/debian/modules/http-lua/src/ngx_http_lua_subrequest.c @@ -1587,6 +1587,7 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) { lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; ngx_http_lua_co_ctx_t *coctx; @@ -1620,6 +1621,7 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, coctx->nsubreqs); @@ -1627,12 +1629,12 @@ ngx_http_lua_subrequest_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } /* rc == NGX_ERROR || rc >= NGX_OK */ diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.c b/debian/modules/http-lua/src/ngx_http_lua_util.c index c7bee3e..df0aae8 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.c +++ b/debian/modules/http-lua/src/ngx_http_lua_util.c @@ -3055,13 +3055,13 @@ ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) /* this is for callers other than the content handler */ ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, - ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx) + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs) { ngx_int_t rc; ngx_http_lua_posted_thread_t *pt; for ( ;; ) { - if (c->destroyed) { + if (c->destroyed || c->requests != nreqs) { return NGX_DONE; } @@ -3461,6 +3461,7 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) { lua_State *vm; ngx_int_t rc; + ngx_uint_t nreqs; ngx_connection_t *c; ngx_http_lua_ctx_t *ctx; @@ -3480,6 +3481,7 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) c = r->connection; vm = ngx_http_lua_get_lua_vm(r, ctx); + nreqs = c->requests; rc = ngx_http_lua_run_thread(vm, r, ctx, 0); @@ -3487,12 +3489,12 @@ ngx_http_lua_on_abort_resume(ngx_http_request_t *r) "lua run thread returned %d", rc); if (rc == NGX_AGAIN) { - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (rc == NGX_DONE) { ngx_http_lua_finalize_request(r, NGX_DONE); - return ngx_http_lua_run_posted_threads(c, vm, r, ctx); + return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs); } if (ctx->entered_content_phase) { diff --git a/debian/modules/http-lua/src/ngx_http_lua_util.h b/debian/modules/http-lua/src/ngx_http_lua_util.h index a37852f..2f995e0 100644 --- a/debian/modules/http-lua/src/ngx_http_lua_util.h +++ b/debian/modules/http-lua/src/ngx_http_lua_util.h @@ -205,7 +205,7 @@ ngx_http_lua_co_ctx_t *ngx_http_lua_create_co_ctx(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); ngx_int_t ngx_http_lua_run_posted_threads(ngx_connection_t *c, lua_State *L, - ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx); + ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_uint_t nreqs); ngx_int_t ngx_http_lua_post_thread(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t *coctx); diff --git a/debian/modules/http-lua/t/000--init.t b/debian/modules/http-lua/t/000--init.t index ad2d70e..dbe2c33 100644 --- a/debian/modules/http-lua/t/000--init.t +++ b/debian/modules/http-lua/t/000--init.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 1); +plan tests => repeat_each() * (blocks() * 3); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; @@ -14,9 +14,13 @@ our $http_config = <<'_EOC_'; drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql dbname=ngx_test user=ngx_test password=ngx_test; } + + lua_package_path "../lua-resty-mysql/lib/?.lua;;"; _EOC_ no_shuffle(); +no_long_string(); + run_tests(); __DATA__ @@ -25,51 +29,46 @@ __DATA__ --- http_config eval: $::http_config --- config location = /init { - drizzle_pass database; - drizzle_query "DROP TABLE IF EXISTS conv_uid"; + content_by_lua_block { + local mysql = require "resty.mysql" + local db = assert(mysql:new()) + local ok, err, errcode, sqlstate = db:connect{ + host = "127.0.0.1", + port = $TEST_NGINX_MYSQL_PORT, + database = "ngx_test", + user = "ngx_test", + password = "ngx_test", + charset = "utf8", + } + + local queries = { + "DROP TABLE IF EXISTS conv_uid", + "CREATE TABLE conv_uid(id serial primary key, new_uid integer, old_uid integer)", + "INSERT INTO conv_uid(old_uid,new_uid) VALUES(32,56),(35,78)", + } + + for _, query in ipairs(queries) do + local ok, err = db:query(query) + if not ok then + ngx.say("failed to run mysql query \"", query, "\": ", err) + return + end + end + + ngx.say("done!") + } } --- request GET /init ---- error_code: 200 +--- response_body +done! --- timeout: 10 --- no_error_log [error] -=== TEST 2: conv_uid - create table ---- http_config eval: $::http_config ---- config - location = /init { - drizzle_pass database; - drizzle_query "CREATE TABLE conv_uid(id serial primary key, new_uid integer, old_uid integer)"; - } ---- request -GET /init ---- error_code: 200 ---- timeout: 10 ---- no_error_log -[error] - - - -=== TEST 3: conv_uid - insert value ---- http_config eval: $::http_config ---- config - location = /init { - drizzle_pass database; - drizzle_query "INSERT INTO conv_uid(old_uid,new_uid) VALUES(32,56),(35,78)"; - } ---- request -GET /init ---- error_code: 200 ---- timeout: 10 ---- no_error_log -[error] - - - -=== TEST 4: flush data from memcached +=== TEST 2: flush data from memcached --- config location /flush { set $memc_cmd flush_all; diff --git a/debian/modules/http-lua/t/002-content.t b/debian/modules/http-lua/t/002-content.t index 3f2460e..cc92d6f 100644 --- a/debian/modules/http-lua/t/002-content.t +++ b/debian/modules/http-lua/t/002-content.t @@ -10,7 +10,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 19); +plan tests => repeat_each() * (blocks() * 2 + 23); #no_diff(); #no_long_string(); @@ -539,6 +539,9 @@ GET /main Content-Length: 12 --- response_body chop hello, world +--- no_error_log +[error] +[alert] @@ -761,6 +764,9 @@ Content-Length: 13 hello, world --- timeout: 5 +--- no_error_log +[error] +[alert] diff --git a/debian/modules/http-lua/t/004-require.t b/debian/modules/http-lua/t/004-require.t index ec74116..35e04db 100644 --- a/debian/modules/http-lua/t/004-require.t +++ b/debian/modules/http-lua/t/004-require.t @@ -35,6 +35,7 @@ __DATA__ location /load { content_by_lua ' package.loaded.foo = nil; + collectgarbage() local foo = require "foo"; foo.hi() '; diff --git a/debian/modules/http-lua/t/017-exec.t b/debian/modules/http-lua/t/017-exec.t index 535c4ab..544b8bb 100644 --- a/debian/modules/http-lua/t/017-exec.t +++ b/debian/modules/http-lua/t/017-exec.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 4); +plan tests => repeat_each() * (blocks() * 2 + 8); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; @@ -572,3 +572,25 @@ hello, bah ["dummy", "dummy"] --- no_error_log [error] + + + +=== TEST 25: pipelined requests +--- config + location /t { + content_by_lua_block { + ngx.exec("@foo") + } + } + + location @foo { + return 200; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- error_code eval +[200, 200] +--- response_body eval +["", ""] +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/023-rewrite/exec.t b/debian/modules/http-lua/t/023-rewrite/exec.t index bd97968..edd4607 100644 --- a/debian/modules/http-lua/t/023-rewrite/exec.t +++ b/debian/modules/http-lua/t/023-rewrite/exec.t @@ -5,7 +5,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); #repeat_each(1); -plan tests => blocks() * repeat_each() * 2; +plan tests => repeat_each() * (blocks() * 2 + 4); #no_diff(); #no_long_string(); @@ -376,3 +376,25 @@ ngx.exec("@proxy") GET /main --- response_body hello, bah + + + +=== TEST 17: pipelined requests +--- config + location /t { + rewrite_by_lua_block { + ngx.exec("@foo") + } + } + + location @foo { + return 200; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- error_code eval +[200, 200] +--- response_body eval +["", ""] +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t index 15bec7f..a32ed7b 100644 --- a/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t @@ -24,7 +24,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 14); +plan tests => repeat_each() * (blocks() * 4 + 8); our $HtmlDir = html_dir; @@ -174,7 +174,7 @@ lua tcp socket connect timeout: 102 -=== TEST 5: sock:settimeout(-1) does not override lua_socket_connect_timeout +=== TEST 5: -1 is bad timeout value --- config server_tokens off; lua_socket_connect_timeout 102ms; @@ -198,14 +198,12 @@ lua tcp socket connect timeout: 102 } --- request GET /t5 ---- response_body -failed to connect: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket connect timeout: 102 ---- no_error_log -[error] -[alert] +bad timeout value --- timeout: 10 +--- error_code: 500 @@ -371,7 +369,7 @@ lua tcp socket read timed out -=== TEST 10: sock:settimeout(-1) does not override lua_socket_read_timeout +=== TEST 10: -1 is bad timeout value --- config server_tokens off; lua_socket_read_timeout 102ms; @@ -385,8 +383,6 @@ lua tcp socket read timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local line @@ -402,13 +398,12 @@ lua tcp socket read timed out } --- request GET /t ---- response_body -connected: 1 -failed to receive: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket read timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket read timed out +bad timeout value +--- timeout: 10 +--- error_code: 500 @@ -574,7 +569,7 @@ lua tcp socket write timed out -=== TEST 15: sock:settimeout(-1) does not override lua_socket_send_timeout +=== TEST 15: -1 is bad timeout value --- config server_tokens off; lua_socket_send_timeout 102ms; @@ -588,8 +583,6 @@ lua tcp socket write timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local bytes @@ -605,10 +598,9 @@ lua tcp socket write timed out } --- request GET /t ---- response_body -connected: 1 -failed to send: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket send timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket write timed out +bad timeout value +--- timeout: 10 +--- error_code: 500 diff --git a/debian/modules/http-lua/t/024-access/exec.t b/debian/modules/http-lua/t/024-access/exec.t index 3fb87be..43c1a77 100644 --- a/debian/modules/http-lua/t/024-access/exec.t +++ b/debian/modules/http-lua/t/024-access/exec.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 2); +plan tests => repeat_each() * (blocks() * 2 + 6); #no_diff(); #no_long_string(); @@ -369,3 +369,25 @@ GET /read 'unsafe URI "/hi/../" was detected', qr/runtime error: access_by_lua\(nginx.conf:\d+\):2: unsafe uri/, ] + + + +=== TEST 17: pipelined requests +--- config + location /t { + access_by_lua_block { + ngx.exec("@foo") + } + } + + location @foo { + return 200; + } +--- pipelined_requests eval +["GET /t", "GET /t"] +--- error_code eval +[200, 200] +--- response_body eval +["", ""] +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/035-gmatch.t b/debian/modules/http-lua/t/035-gmatch.t index 5b63ae4..0426997 100644 --- a/debian/modules/http-lua/t/035-gmatch.t +++ b/debian/modules/http-lua/t/035-gmatch.t @@ -440,6 +440,7 @@ done location /main { content_by_lua ' package.loaded.foo = nil + collectgarbage() local res = ngx.location.capture("/t") if res.status == 200 then diff --git a/debian/modules/http-lua/t/058-tcp-socket.t b/debian/modules/http-lua/t/058-tcp-socket.t index 1ee113b..0743dd7 100644 --- a/debian/modules/http-lua/t/058-tcp-socket.t +++ b/debian/modules/http-lua/t/058-tcp-socket.t @@ -4,7 +4,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * 190; +plan tests => repeat_each() * 193; our $HtmlDir = html_dir; @@ -3690,3 +3690,40 @@ received: OK close: 1 nil --- no_error_log [error] + + + +=== TEST 61: resolver send query failing immediately in connect() +this case did not clear coctx->cleanup properly and would lead to memory invalid accesses. + +this test case requires the following iptables rule to work properly: + +sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT + +--- config + location /t { + resolver 127.0.0.1:10086 ipv6=off; + resolver_timeout 10ms; + + content_by_lua_block { + local sock = ngx.socket.tcp() + + for i = 1, 3 do -- retry + local ok, err = sock:connect("www.google.com", 80) + if not ok then + ngx.say("failed to connect: ", err) + end + end + + ngx.say("hello!") + } + } +--- request +GET /t +--- response_body +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved +failed to connect: www.google.com could not be resolved +hello! +--- error_log eval +qr{\[alert\] .*? send\(\) failed \(\d+: Operation not permitted\) while resolving} diff --git a/debian/modules/http-lua/t/065-tcp-socket-timeout.t b/debian/modules/http-lua/t/065-tcp-socket-timeout.t index 212766e..9e5460e 100644 --- a/debian/modules/http-lua/t/065-tcp-socket-timeout.t +++ b/debian/modules/http-lua/t/065-tcp-socket-timeout.t @@ -28,7 +28,7 @@ our $StapScript = $t::StapThread::StapScript; repeat_each(2); -plan tests => repeat_each() * (blocks() * 4 + 12); +plan tests => repeat_each() * (blocks() * 4 + 6); our $HtmlDir = html_dir; @@ -159,7 +159,7 @@ lua tcp socket connect timed out -=== TEST 5: sock:settimeout(-1) does not override lua_socket_connect_timeout +=== TEST 5: -1 is bad timeout value --- config server_tokens off; lua_socket_connect_timeout 102ms; @@ -179,11 +179,11 @@ lua tcp socket connect timed out } --- request GET /t ---- response_body -failed to connect: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket connect timeout: 102 -lua tcp socket connect timed out +bad timeout value +--- error_code: 500 @@ -342,7 +342,7 @@ lua tcp socket read timed out -=== TEST 10: sock:settimeout(-1) does not override lua_socket_read_timeout +=== TEST 10: -1 is bad timeout value --- config server_tokens off; lua_socket_read_timeout 102ms; @@ -356,8 +356,6 @@ lua tcp socket read timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local line @@ -371,13 +369,11 @@ lua tcp socket read timed out } --- request GET /t ---- response_body -connected: 1 -failed to receive: timeout +--- response_body_like chomp +500 Internal Server Error +--- error_code: 500 --- error_log -lua tcp socket read timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket read timed out +bad timeout value @@ -563,8 +559,6 @@ lua tcp socket write timed out return end - ngx.say("connected: ", ok) - sock:settimeout(-1) local bytes @@ -578,13 +572,11 @@ lua tcp socket write timed out } --- request GET /t ---- response_body -connected: 1 -failed to send: timeout +--- response_body_like chomp +500 Internal Server Error --- error_log -lua tcp socket send timeout: 102 -lua tcp socket connect timeout: 60000 -lua tcp socket write timed out +bad timeout value +--- error_code: 500 @@ -994,3 +986,33 @@ close: 1 nil --- no_error_log [error] + + + +=== TEST 23: timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeout, sock, (2 ^ 31) - 1) + if not ok then + ngx.say("failed to set timeout: ", err) + else + ngx.say("settimeout: ok") + end + + ok, err = pcall(sock.settimeout, sock, 2 ^ 31) + if not ok then + ngx.say("failed to set timeout: ", err) + else + ngx.say("settimeout: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeout: ok +failed to set timeout: bad timeout value +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/097-uthread-rewrite.t b/debian/modules/http-lua/t/097-uthread-rewrite.t index a93adc8..2f0c06f 100644 --- a/debian/modules/http-lua/t/097-uthread-rewrite.t +++ b/debian/modules/http-lua/t/097-uthread-rewrite.t @@ -258,6 +258,7 @@ free request hello foo --- no_error_log [error] +--- wait: 0.1 diff --git a/debian/modules/http-lua/t/106-timer.t b/debian/modules/http-lua/t/106-timer.t index 04a532e..3e4741e 100644 --- a/debian/modules/http-lua/t/106-timer.t +++ b/debian/modules/http-lua/t/106-timer.t @@ -174,7 +174,7 @@ qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:4[4-9]|5[0-6]) local begin = ngx.now() local function f() print("my lua timer handler") - ngx.sleep(0.02) + ngx.sleep(0.2) print("elapsed: ", ngx.now() - begin) end local ok, err = ngx.timer.at(0.05, f) @@ -199,7 +199,7 @@ delete thread 2 --- response_body registered timer ---- wait: 0.12 +--- wait: 0.3 --- no_error_log [error] [alert] @@ -208,7 +208,7 @@ registered timer --- error_log eval [ qr/\[lua\] .*? my lua timer handler/, -qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.0(?:6[4-9]|7[0-6])/, +qr/\[lua\] content_by_lua\(nginx\.conf:\d+\):\d+: elapsed: 0\.(?:1[4-9]|2[0-6]?)/, "lua ngx.timer expired", "http lua close fake http connection" ] diff --git a/debian/modules/http-lua/t/129-ssl-socket.t b/debian/modules/http-lua/t/129-ssl-socket.t index 1c3f7cd..e7447a7 100644 --- a/debian/modules/http-lua/t/129-ssl-socket.t +++ b/debian/modules/http-lua/t/129-ssl-socket.t @@ -1181,7 +1181,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log lua ssl server name: "openresty.org" -SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 --- no_error_log SSL reused session [error] @@ -1261,7 +1261,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log lua ssl server name: "openresty.org" -SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-SHA +SSL: TLSv1.2, cipher: "ECDHE-RSA-AES256-SHA SSLv3 --- no_error_log SSL reused session [error] @@ -1341,7 +1341,7 @@ lua ssl free session: ([0-9A-F]+):1 $/ --- error_log lua ssl server name: "openresty.org" -SSL: TLSv1, cipher: "ECDHE-RSA-AES256-SHA +SSL: TLSv1, cipher: "ECDHE-RSA-AES128-SHA SSLv3 --- no_error_log SSL reused session [error] diff --git a/debian/modules/http-lua/t/139-ssl-cert-by.t b/debian/modules/http-lua/t/139-ssl-cert-by.t index c13044f..b521e9e 100644 --- a/debian/modules/http-lua/t/139-ssl-cert-by.t +++ b/debian/modules/http-lua/t/139-ssl-cert-by.t @@ -113,11 +113,17 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_certificate_by_lua:1: ssl cert by lua is running! --- no_error_log [error] [alert] +--- grep_error_log eval: qr/ssl_certificate_by_lua:.*?,|\bssl cert: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log_out eval +qr/reusable connection: 1 +ssl cert: connection reusable: 1 +reusable connection: 0 +ssl_certificate_by_lua:1: ssl cert by lua is running!, +/ diff --git a/debian/modules/http-lua/t/142-ssl-session-store.t b/debian/modules/http-lua/t/142-ssl-session-store.t index 73b6e19..825d016 100644 --- a/debian/modules/http-lua/t/142-ssl-session-store.t +++ b/debian/modules/http-lua/t/142-ssl-session-store.t @@ -82,11 +82,16 @@ close: 1 nil --- error_log lua ssl server name: "test.com" -ssl_session_store_by_lua_block:1: ssl session store by lua is running! --- no_error_log [error] [alert] +--- grep_error_log eval: qr/ssl_session_store_by_lua_block:.*?,|\bssl session store: connection reusable: \d+|\breusable connection: \d+/ +--- grep_error_log_out eval +qr/^reusable connection: 0 +ssl session store: connection reusable: 0 +ssl_session_store_by_lua_block:1: ssl session store by lua is running!, +/m, diff --git a/debian/modules/http-lua/t/143-ssl-session-fetch.t b/debian/modules/http-lua/t/143-ssl-session-fetch.t index 701ead7..7be180f 100644 --- a/debian/modules/http-lua/t/143-ssl-session-fetch.t +++ b/debian/modules/http-lua/t/143-ssl-session-fetch.t @@ -83,16 +83,21 @@ connected: 1 ssl handshake: userdata close: 1 nil ---- grep_error_log eval -qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s +--- grep_error_log eval: qr/ssl_session_fetch_by_lua_block:.*?,|\bssl session fetch: connection reusable: \d+|\breusable connection: \d+/ --- grep_error_log_out eval [ -'', -'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! -', -'ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running! -', +qr/\A(?:reusable connection: [01]\n)+\z/s, +qr/^reusable connection: 1 +ssl session fetch: connection reusable: 1 +reusable connection: 0 +ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +/m, +qr/^reusable connection: 1 +ssl session fetch: connection reusable: 1 +reusable connection: 0 +ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, +/m, ] --- no_error_log diff --git a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t index 0689a9b..8199e84 100644 --- a/debian/modules/http-lua/t/147-tcp-socket-timeouts.t +++ b/debian/modules/http-lua/t/147-tcp-socket-timeouts.t @@ -532,3 +532,96 @@ received: ok failed to receive a line: closed [] --- no_error_log [error] + + + +=== TEST 8: connection timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeouts, sock, + (2 ^ 31) - 1, 500, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + + ok, err = pcall(sock.settimeouts, sock, 2 ^ 31, 500, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeouts: ok +failed to set timeouts: bad timeout value +--- no_error_log +[error] + + + +=== TEST 9: send timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeouts, sock, + 500, (2 ^ 31) - 1, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + + ok, err = pcall(sock.settimeouts, sock, 500, 2 ^ 31, 500) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeouts: ok +failed to set timeouts: bad timeout value +--- no_error_log +[error] + + + +=== TEST 10: read timeout overflow detection +--- config + location /t { + content_by_lua_block { + local sock = ngx.socket.tcp() + local ok, err = pcall(sock.settimeouts, sock, + 500, 500, (2 ^ 31) - 1) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + + ok, err = pcall(sock.settimeouts, sock, 500, 500, 2 ^ 31) + if not ok then + ngx.say("failed to set timeouts: ", err) + else + ngx.say("settimeouts: ok") + end + } + } +--- request +GET /t +--- response_body_like +settimeouts: ok +failed to set timeouts: bad timeout value +--- no_error_log +[error] diff --git a/debian/modules/http-lua/t/154-semaphore.t b/debian/modules/http-lua/t/154-semaphore.t index 3c1f004..875f181 100644 --- a/debian/modules/http-lua/t/154-semaphore.t +++ b/debian/modules/http-lua/t/154-semaphore.t @@ -75,6 +75,7 @@ semaphore gc wait queue is not empty === TEST 2: timer + shutdown error log (lua code cache off) +FIXME: this test case leaks memory. --- http_config lua_code_cache off; --- config @@ -116,3 +117,4 @@ hello, world --- shutdown_error_log --- no_shutdown_error_log semaphore gc wait queue is not empty +--- SKIP diff --git a/debian/modules/http-lua/util/build.sh b/debian/modules/http-lua/util/build.sh index e45c00a..164bf9f 100755 --- a/debian/modules/http-lua/util/build.sh +++ b/debian/modules/http-lua/util/build.sh @@ -23,6 +23,7 @@ force=$2 #--with-http_spdy_module \ time ngx-build $force $version \ + --with-pcre-jit \ --with-ipv6 \ --with-cc-opt="-I$PCRE_INC -I$OPENSSL_INC" \ --with-http_v2_module \ @@ -35,6 +36,8 @@ time ngx-build $force $version \ --without-mail_imap_module \ --with-http_image_filter_module \ --without-mail_smtp_module \ + --with-stream \ + --with-stream_ssl_module \ --without-http_upstream_ip_hash_module \ --without-http_memcached_module \ --without-http_auth_basic_module \ @@ -50,6 +53,7 @@ time ngx-build $force $version \ --add-module=$root/../rds-json-nginx-module \ --add-module=$root/../coolkit-nginx-module \ --add-module=$root/../redis2-nginx-module \ + --add-module=$root/../stream-lua-nginx-module \ --add-module=$root/t/data/fake-module \ --add-module=$root/t/data/fake-shm-module \ --add-module=$root/t/data/fake-delayed-load-module \ diff --git a/debian/modules/http-lua/valgrind.suppress b/debian/modules/http-lua/valgrind.suppress index d0bcc56..7273986 100644 --- a/debian/modules/http-lua/valgrind.suppress +++ b/debian/modules/http-lua/valgrind.suppress @@ -1,16 +1,16 @@ { - -Memcheck:Addr1 -fun:ngx_init_cycle -fun:ngx_master_process_cycle -fun:main + + Memcheck:Addr1 + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main } { - -Memcheck:Addr4 -fun:ngx_init_cycle -fun:ngx_master_process_cycle -fun:main + + Memcheck:Addr4 + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main } { @@ -104,11 +104,11 @@ fun:main fun:ngx_event_process_init } { - - Memcheck:Param - sendmsg(mmsg[0].msg_hdr) - fun:sendmmsg - fun:__libc_res_nsend + + Memcheck:Param + sendmsg(mmsg[0].msg_hdr) + fun:sendmmsg + fun:__libc_res_nsend } { @@ -120,11 +120,11 @@ fun:main fun:ngx_start_cache_manager_processes } { - - Memcheck:Cond - fun:ngx_init_cycle - fun:ngx_master_process_cycle - fun:main + + Memcheck:Cond + fun:ngx_init_cycle + fun:ngx_master_process_cycle + fun:main } { @@ -157,10 +157,36 @@ fun:main fun:ngx_alloc fun:ngx_set_environment fun:ngx_single_process_cycle - fun:main } { Memcheck:Cond obj:* } +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_worker_process_init +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_create_pool + fun:main +} +{ + + Memcheck:Leak + match-leak-kinds: definite + fun:malloc + fun:ngx_alloc + fun:ngx_set_environment + fun:ngx_single_process_cycle +} diff --git a/debian/modules/patches/http-lua/openssl-1.1.0.patch b/debian/modules/patches/http-lua/openssl-1.1.0.patch index 431031b..4dafce2 100644 --- a/debian/modules/patches/http-lua/openssl-1.1.0.patch +++ b/debian/modules/patches/http-lua/openssl-1.1.0.patch @@ -1,4 +1,4 @@ -From 525d5a550f5f256af01de1264358086a4cd1ac4a Mon Sep 17 00:00:00 2001 +From 47ab0d4eca3fa62403c798d7dfad50a5f9f7215a Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:31:32 +0100 Subject: [PATCH 1/4] bugfix: ssl: don't use SSLv3 in tests. @@ -11,7 +11,7 @@ tickets set ssl_session_tickets to off instead. 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/t/142-ssl-session-store.t b/t/142-ssl-session-store.t -index 73b6e197..260fe490 100644 +index 825d0163..cc3a664c 100644 --- a/t/142-ssl-session-store.t +++ b/t/142-ssl-session-store.t @@ -32,7 +32,7 @@ __DATA__ @@ -23,7 +23,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -102,7 +102,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running! +@@ -107,7 +107,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running!, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -32,7 +32,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -177,7 +177,7 @@ API disabled in the context of ssl_session_store_by_lua* +@@ -182,7 +182,7 @@ API disabled in the context of ssl_session_store_by_lua* server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -41,7 +41,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -267,9 +267,9 @@ my timer run! +@@ -272,9 +272,9 @@ my timer run! listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -52,7 +52,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -335,9 +335,9 @@ API disabled in the context of ssl_session_store_by_lua* +@@ -340,9 +340,9 @@ API disabled in the context of ssl_session_store_by_lua* server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -63,7 +63,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -407,9 +407,9 @@ ngx.exit does not yield and the error code is eaten. +@@ -412,9 +412,9 @@ ngx.exit does not yield and the error code is eaten. server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -74,7 +74,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -480,9 +480,9 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 +@@ -485,9 +485,9 @@ ssl_session_store_by_lua*: handler return value: 0, sess new cb exit code: 0 server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -85,7 +85,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -548,9 +548,9 @@ should never reached here +@@ -553,9 +553,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -96,7 +96,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -621,7 +621,7 @@ get_phase: ssl_session_store +@@ -626,7 +626,7 @@ get_phase: ssl_session_store } ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -105,7 +105,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -690,7 +690,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, +@@ -695,7 +695,7 @@ qr/elapsed in ssl cert by lua: 0.(?:09|1[01])\d+,/, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -114,7 +114,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } -@@ -760,7 +760,6 @@ a.lua:1: ssl store session by lua is running! +@@ -765,7 +765,6 @@ a.lua:1: ssl store session by lua is running! ssl_session_store_by_lua_block { print("handler in test.com") } @@ -122,7 +122,7 @@ index 73b6e197..260fe490 100644 ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; -@@ -770,7 +769,6 @@ a.lua:1: ssl store session by lua is running! +@@ -775,7 +774,6 @@ a.lua:1: ssl store session by lua is running! server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -130,7 +130,7 @@ index 73b6e197..260fe490 100644 ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; -@@ -836,7 +834,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here +@@ -841,7 +839,7 @@ qr/\[emerg\] .*? "ssl_session_store_by_lua_block" directive is not allowed here server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -140,7 +140,7 @@ index 73b6e197..260fe490 100644 server_tokens off; } diff --git a/t/143-ssl-session-fetch.t b/t/143-ssl-session-fetch.t -index 701ead72..3626f0fb 100644 +index 7be180f8..4dc992d3 100644 --- a/t/143-ssl-session-fetch.t +++ b/t/143-ssl-session-fetch.t @@ -33,7 +33,7 @@ __DATA__ @@ -152,7 +152,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -114,7 +114,7 @@ qr/ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!/s +@@ -119,7 +119,7 @@ ssl_session_fetch_by_lua_block:1: ssl fetch sess by lua is running!, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -161,7 +161,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -198,7 +198,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, +@@ -203,7 +203,7 @@ qr/elapsed in ssl fetch session by lua: 0.(?:09|1[01])\d+,/, server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -170,7 +170,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -297,9 +297,9 @@ qr/my timer run!/s +@@ -302,9 +302,9 @@ qr/my timer run!/s server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -181,7 +181,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -377,9 +377,9 @@ qr/received memc reply: OK/s +@@ -382,9 +382,9 @@ qr/received memc reply: OK/s server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -192,7 +192,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -458,9 +458,9 @@ should never reached here +@@ -463,9 +463,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -203,7 +203,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -540,9 +540,9 @@ should never reached here +@@ -545,9 +545,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -214,7 +214,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -621,9 +621,9 @@ should never reached here +@@ -626,9 +626,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -225,7 +225,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -704,9 +704,9 @@ should never reached here +@@ -709,9 +709,9 @@ should never reached here server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; @@ -236,7 +236,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -787,7 +787,7 @@ should never reached here +@@ -792,7 +792,7 @@ should never reached here server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -245,7 +245,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -872,7 +872,7 @@ qr/get_phase: ssl_session_fetch/s +@@ -877,7 +877,7 @@ qr/get_phase: ssl_session_fetch/s } ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -254,7 +254,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -956,7 +956,7 @@ ssl store session by lua is running! +@@ -961,7 +961,7 @@ ssl store session by lua is running! server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -263,7 +263,7 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -@@ -1036,7 +1036,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s +@@ -1041,7 +1041,7 @@ qr/\S+:\d+: ssl fetch sess by lua is running!/s server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; @@ -273,10 +273,10 @@ index 701ead72..3626f0fb 100644 server_tokens off; } -- -2.14.1 +2.15.1 -From d308b44b3daf7702d9218e2a5620a89a5eca8389 Mon Sep 17 00:00:00 2001 +From 5cb24ce5eccd580d1bd6a2c44d7ea3cef5ad7740 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Thu, 12 May 2016 13:12:23 +0100 Subject: [PATCH 2/4] bugfix: ssl: do not access SSL_SESSION struct directly. @@ -288,10 +288,10 @@ In OpenSSL 1.1.0 it was made opaque. 2 files changed, 80 insertions(+), 83 deletions(-) diff --git a/src/ngx_http_lua_socket_tcp.c b/src/ngx_http_lua_socket_tcp.c -index 382a94de..07164746 100644 +index f0988bc5..17d3db2e 100644 --- a/src/ngx_http_lua_socket_tcp.c +++ b/src/ngx_http_lua_socket_tcp.c -@@ -1316,9 +1316,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) +@@ -1320,9 +1320,8 @@ ngx_http_lua_socket_tcp_sslhandshake(lua_State *L) return 2; } @@ -303,7 +303,7 @@ index 382a94de..07164746 100644 } } -@@ -1583,9 +1582,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, +@@ -1587,9 +1586,8 @@ ngx_http_lua_ssl_handshake_retval_handler(ngx_http_request_t *r, } else { *ud = ssl_session; @@ -315,7 +315,7 @@ index 382a94de..07164746 100644 /* set up the __gc metamethod */ lua_pushlightuserdata(L, &ngx_http_lua_ssl_session_metatable_key); -@@ -5365,9 +5363,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) +@@ -5386,9 +5384,8 @@ ngx_http_lua_ssl_free_session(lua_State *L) psession = lua_touserdata(L, 1); if (psession && *psession != NULL) { @@ -328,7 +328,7 @@ index 382a94de..07164746 100644 ngx_ssl_free_session(*psession); } diff --git a/t/129-ssl-socket.t b/t/129-ssl-socket.t -index 1c3f7cd0..0cd1f52f 100644 +index e7447a7c..c4bce9e0 100644 --- a/t/129-ssl-socket.t +++ b/t/129-ssl-socket.t @@ -108,10 +108,10 @@ sent http request: 59 bytes. @@ -714,10 +714,10 @@ index 1c3f7cd0..0cd1f52f 100644 --- error_log lua ssl certificate verify error: (18: self signed certificate) -- -2.14.1 +2.15.1 -From 473c121668c658140dffdbeb70aa7df1fc48d2a7 Mon Sep 17 00:00:00 2001 +From 567bca126f4b9e71fbf9d473e85b975f190dcd3c Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Fri, 10 Jun 2016 13:23:21 +0100 Subject: [PATCH 3/4] bugfix: ssl: do not access SSL struct directly for @@ -745,10 +745,10 @@ index 31b4f243..9ec8b509 100644 return NGX_DECLINED; } -- -2.14.1 +2.15.1 -From 44988918835b8b41e51e75c1618250a560bc11ca Mon Sep 17 00:00:00 2001 +From 840ad10b8447f9ea1f0ddede344916d423029e67 Mon Sep 17 00:00:00 2001 From: Alessandro Ghedini Date: Tue, 13 Sep 2016 22:19:10 +0100 Subject: [PATCH 4/4] bugfix: ssl: make SSL session callback build with OpenSSL @@ -761,7 +761,7 @@ Subject: [PATCH 4/4] bugfix: ssl: make SSL session callback build with OpenSSL 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/ngx_http_lua_ssl_session_fetchby.c b/src/ngx_http_lua_ssl_session_fetchby.c -index 556b7320..5289cb92 100644 +index 3a3c1f54..2c75f6a9 100644 --- a/src/ngx_http_lua_ssl_session_fetchby.c +++ b/src/ngx_http_lua_ssl_session_fetchby.c @@ -171,8 +171,11 @@ ngx_http_lua_ssl_sess_fetch_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, @@ -778,7 +778,7 @@ index 556b7320..5289cb92 100644 { lua_State *L; ngx_int_t rc; -@@ -284,7 +287,7 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, +@@ -287,7 +290,7 @@ ngx_http_lua_ssl_sess_fetch_handler(ngx_ssl_conn_t *ssl_conn, u_char *id, cctx->exit_code = 1; /* successful by default */ cctx->connection = c; cctx->request = r; @@ -805,7 +805,7 @@ index 5a6f96f5..50c6616d 100644 diff --git a/src/ngx_http_lua_ssl_session_storeby.c b/src/ngx_http_lua_ssl_session_storeby.c -index bae8273d..dc1fad9b 100644 +index f83e85d9..ce832ea1 100644 --- a/src/ngx_http_lua_ssl_session_storeby.c +++ b/src/ngx_http_lua_ssl_session_storeby.c @@ -172,6 +172,8 @@ int @@ -817,7 +817,7 @@ index bae8273d..dc1fad9b 100644 lua_State *L; ngx_int_t rc; ngx_connection_t *c, *fc = NULL; -@@ -246,11 +248,13 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, +@@ -247,11 +249,13 @@ ngx_http_lua_ssl_sess_store_handler(ngx_ssl_conn_t *ssl_conn, } } @@ -834,5 +834,5 @@ index bae8273d..dc1fad9b 100644 dd("setting cctx"); -- -2.14.1 +2.15.1 From 72b4f71671c9f87f63be9db63f7f821c41aead92 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:23:07 +0200 Subject: [PATCH 048/414] http-dav-ext: Upgrade to 0.1.0 Closes: #878611 --- debian/modules/control | 3 +- debian/modules/http-dav-ext/LICENSE | 22 ++++++++++ debian/modules/http-dav-ext/README | 29 ------------- debian/modules/http-dav-ext/README.rst | 41 +++++++++++++++++++ debian/modules/http-dav-ext/config | 19 ++++++--- .../http-dav-ext/ngx_http_dav_ext_module.c | 9 ++-- .../patches/http-dav-ext/dynamic-module.patch | 41 ------------------- debian/modules/patches/http-dav-ext/series | 1 - 8 files changed, 83 insertions(+), 82 deletions(-) create mode 100644 debian/modules/http-dav-ext/LICENSE delete mode 100644 debian/modules/http-dav-ext/README create mode 100644 debian/modules/http-dav-ext/README.rst delete mode 100644 debian/modules/patches/http-dav-ext/dynamic-module.patch delete mode 100644 debian/modules/patches/http-dav-ext/series diff --git a/debian/modules/control b/debian/modules/control index bd7cc0a..6552957 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -50,8 +50,7 @@ Patch: Module: http-dav-ext Homepage: https://github.com/arut/nginx-dav-ext-module -Version: v0.0.3 -Patch: dynamic-module.patch +Version: v0.1.0 Module: http-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex diff --git a/debian/modules/http-dav-ext/LICENSE b/debian/modules/http-dav-ext/LICENSE new file mode 100644 index 0000000..7be3135 --- /dev/null +++ b/debian/modules/http-dav-ext/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012-2017, Roman Arutyunyan +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 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 OWNER 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/debian/modules/http-dav-ext/README b/debian/modules/http-dav-ext/README deleted file mode 100644 index bc727ff..0000000 --- a/debian/modules/http-dav-ext/README +++ /dev/null @@ -1,29 +0,0 @@ -== nginx-dav-ext-module == - -NGINX WebDAV missing commands support (PROPFIND & OPTIONS) - -(c) 2012 Arutyunyan Roman (arut@qip.ru) - - -For full WebDAV support in NGINX you need to turn on standard NGINX -WebDAV module (providing partial WebDAV implementation) as well as -this module for missing methods - -./configure --with-http_dav_module --add-module= - - - -Requirements: - - libexpat-dev - - -Example config: - - location / { - - dav_methods PUT DELETE MKCOL COPY MOVE; - dav_ext_methods PROPFIND OPTIONS; - - root /var/root/; - } diff --git a/debian/modules/http-dav-ext/README.rst b/debian/modules/http-dav-ext/README.rst new file mode 100644 index 0000000..91c10e3 --- /dev/null +++ b/debian/modules/http-dav-ext/README.rst @@ -0,0 +1,41 @@ +******************** +nginx-dav-ext-module +******************** + +NGINX WebDAV missing commands support (PROPFIND & OPTIONS) + +Copyright |copy| 2012-2017 Arutyunyan Roman (arutyunyan.roman@gmail.com) + +.. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN + +For full WebDAV support in NGINX you need to enable the standard NGINX +WebDAV module (providing partial WebDAV implementation) as well as +this module for missing methods: + +.. code-block:: bash + + $ ./configure --with-http_dav_module --add-module=/path/to/this-module + +The module can be built dynamically: + +.. code-block:: bash + + $ ./configure --with-http_dav_module --add-dynamic-module=/path/to/this-module + +Requirements +============ + +``libexpat-dev`` + + +Example config +============== + +.. code-block:: + + location / { + dav_methods PUT DELETE MKCOL COPY MOVE; + dav_ext_methods PROPFIND OPTIONS; + + root /var/root/; + } diff --git a/debian/modules/http-dav-ext/config b/debian/modules/http-dav-ext/config index 98b2b7a..372620b 100644 --- a/debian/modules/http-dav-ext/config +++ b/debian/modules/http-dav-ext/config @@ -1,9 +1,16 @@ -ngx_addon_name="ngx_http_dav_ext_module" +ngx_addon_name=ngx_http_dav_ext_module -HTTP_MODULES="$HTTP_MODULES \ - ngx_http_dav_ext_module" +if [ -f auto/module ] ; then -NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ - $ngx_addon_dir/ngx_http_dav_ext_module.c" + ngx_module_type=HTTP + ngx_module_name=ngx_http_dav_ext_module + ngx_module_libs=-lexpat + ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" -CORE_LIBS="$CORE_LIBS -lexpat" + . auto/module + +else + HTTP_MODULES="$HTTP_MODULES ngx_http_dav_ext_module" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_dav_ext_module.c" + CORE_LIBS="$CORE_LIBS -lexpat" +fi diff --git a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c index 73d86de..ae75fc3 100644 --- a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c +++ b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c @@ -1,5 +1,5 @@ /****************************************************************************** - Copyright (c) 2012, Roman Arutyunyan (arut@qip.ru) + Copyright (c) 2012-2017, Roman Arutyunyan (arutyunyan.roman@gmail.com) All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -535,9 +535,12 @@ ngx_http_dav_ext_send_propfind(ngx_http_request_t *r) u_char *p, *uc; if (ngx_http_variable_unknown_header(&vv, &depth_name, - &r->headers_in.headers.part, 0) == NGX_OK - && vv.valid) + &r->headers_in.headers.part, 0) != NGX_OK) { + return NGX_ERROR; + } + + if (!vv.not_found) { if (vv.len == sizeof("infinity") -1 && !ngx_strncasecmp(vv.data, (u_char*)"infinity", vv.len)) { diff --git a/debian/modules/patches/http-dav-ext/dynamic-module.patch b/debian/modules/patches/http-dav-ext/dynamic-module.patch deleted file mode 100644 index c865460..0000000 --- a/debian/modules/patches/http-dav-ext/dynamic-module.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 0473d8d1bb63a14afe608ecf46bfc933234e3048 Mon Sep 17 00:00:00 2001 -From: Florian Kinder -Date: Fri, 28 Oct 2016 13:34:21 +0200 -Subject: [PATCH] Added dynamic module support -Origin: other, https://github.com/Fank/nginx-dav-ext-module/pull/1 - ---- - config | 22 +++++++++++++++++----- - 1 file changed, 17 insertions(+), 5 deletions(-) - -diff --git a/config b/config -index 98b2b7a..b6b65de 100644 ---- a/config -+++ b/config -@@ -1,9 +1,21 @@ - ngx_addon_name="ngx_http_dav_ext_module" - --HTTP_MODULES="$HTTP_MODULES \ -- ngx_http_dav_ext_module" - --NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ -- $ngx_addon_dir/ngx_http_dav_ext_module.c" -+if test -n "$ngx_module_link"; then -+ ngx_module_type=HTTP -+ ngx_module_name=ngx_http_dav_ext_module -+ ngx_module_incs= -+ ngx_module_deps= -+ ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c" -+ ngx_module_libs="-lexpat" -+ -+ . auto/module -+else -+ CORE_LIBS="$CORE_LIBS -lexpat" - --CORE_LIBS="$CORE_LIBS -lexpat" -+ HTTP_MODULES="$HTTP_MODULES \ -+ ngx_http_dav_ext_module" -+ -+ NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ -+ $ngx_addon_dir/ngx_http_dav_ext_module.c" -+fi diff --git a/debian/modules/patches/http-dav-ext/series b/debian/modules/patches/http-dav-ext/series deleted file mode 100644 index f9b9360..0000000 --- a/debian/modules/patches/http-dav-ext/series +++ /dev/null @@ -1 +0,0 @@ -dynamic-module.patch From ee4b10edd7fc48819c2c5debcbd422af70bcd406 Mon Sep 17 00:00:00 2001 From: Christos Trochalakis Date: Wed, 13 Dec 2017 11:23:19 +0200 Subject: [PATCH 049/414] http-fancyindex: Upgrade to 0.4.2 --- debian/modules/control | 2 +- debian/modules/http-fancyindex/CHANGELOG.md | 21 ++++++- debian/modules/http-fancyindex/README.rst | 32 ++++++++-- .../ngx_http_fancyindex_module.c | 60 +++++++------------ .../http-fancyindex/t/03-exact_size_off.test | 8 +++ .../t/bug61-empty-file-segfault.test | 16 +++++ debian/modules/http-fancyindex/t/run | 2 +- debian/modules/http-fancyindex/template.h | 25 +++----- debian/modules/http-fancyindex/template.html | 25 +++----- 9 files changed, 110 insertions(+), 81 deletions(-) create mode 100644 debian/modules/http-fancyindex/t/03-exact_size_off.test create mode 100644 debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test diff --git a/debian/modules/control b/debian/modules/control index 6552957..a0aa9ba 100644 --- a/debian/modules/control +++ b/debian/modules/control @@ -54,7 +54,7 @@ Version: v0.1.0 Module: http-fancyindex Homepage: https://github.com/aperezdc/ngx-fancyindex -Version: v0.4.1 +Version: v0.4.2 Files-Excluded: .gitignore .travis.yml Module: http-subs-filter diff --git a/debian/modules/http-fancyindex/CHANGELOG.md b/debian/modules/http-fancyindex/CHANGELOG.md index 9d76ae0..6acc50f 100644 --- a/debian/modules/http-fancyindex/CHANGELOG.md +++ b/debian/modules/http-fancyindex/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [0.4.2] - 2017-08-19 +### Changed +- Generated HTML from the default template is now proper HTML5, and it should + pass validation (#52). +- File sizes now have decimal positions when using `fancyindex_exact_size off`. + (Patch by Anders Trier <>.) +- Multiple updates to `README.rst` (Patches by Danila Vershinin + <>, Iulian Onofrei, Lilian Besson, and Nick Geoghegan + <>.) + +### Fixed +- Sorting by file size now also works correctly for directories which contain + files of sizes bigger than `INT_MAX`. (#74, fix suggestion by Chris Young.) +- Custom headers which fail to declare an UTF-8 encoding no longer cause table + header arrows to be rendered incorrectly by browsers (#50). +- Fix segmentation fault when opening directories with empty files (#61, patch + by Catgirl <>.) + ## [0.4.1] - 2016-08-18 ### Added - New `fancyindex_directories_first` configuration directive (enabled by @@ -100,7 +118,8 @@ All notable changes to this project will be documented in this file. - `NEWS.rst` file, to act as change log. -[Unreleased]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.1...HEAD +[Unreleased]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.2...HEAD +[0.4.2]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.1...v0.4.2 [0.4.1]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.6...v0.4.0 [0.3.6]: https://github.com/aperezdc/ngx-fancyindex/compare/v0.3.5...v0.3.6 diff --git a/debian/modules/http-fancyindex/README.rst b/debian/modules/http-fancyindex/README.rst index 93a8206..0e3273c 100644 --- a/debian/modules/http-fancyindex/README.rst +++ b/debian/modules/http-fancyindex/README.rst @@ -26,7 +26,27 @@ server written by `Igor Sysoev `__. Requirements ============ -You will need the sources for Nginx_. Any version starting from the 0.7 +CentOS 7 +~~~~~~~~ + +For users of the `official stable `__ Nginx repository, `extra packages repository with dynamic modules `__ is available and fancyindex is included. + +Install directly:: + + yum install https://extras.getpagespeed.com/redhat/7/x86_64/RPMS/nginx-module-fancyindex-1.12.0.0.4.1-1.el7.gps.x86_64.rpm + +Alternatively, add extras repository first (for future updates) and install the module:: + + yum install nginx-module-fancyindex + +Then load the module in `/etc/nginx/nginx.conf` using + + load_module "modules/ngx_http_fancyindex_module.so"; + +Other platforms +~~~~~~~~~~~~~~~ + +In most other cases you will need the sources for Nginx_. Any version starting from the 0.7 series onwards will work. Note that the modules *might* compile with versions in the 0.6 series by applying ``nginx-0.6-support.patch``, but this is unsupported (YMMV). @@ -58,7 +78,8 @@ Building Since version 0.4.0, the module can also be built as a `dynamic module `_, - using ``--add-dynamic-module=…`` instead. + using ``--add-dynamic-module=…`` instead and ``load_module "modules/ngx_http_fancyindex_module.so";` + in the configuration file 4. Build and install the software:: @@ -92,10 +113,9 @@ achieved using the module: * `Theme `__ by `@TheInsomniac `__. Uses custom header and footer. -* `Theme `__ by - nwrd `__. Uses custom header and footer, the - header includes search field to filter by filename using JavaScript - (`demo `__). +* `Theme `__ by + `Naereen `__. Uses custom header and footer, the + header includes search field to filter by filename using JavaScript. Directives diff --git a/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c index 170167d..10331a5 100644 --- a/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c +++ b/debian/modules/http-fancyindex/ngx_http_fancyindex_module.c @@ -190,6 +190,10 @@ static ngx_conf_enum_t ngx_http_fancyindex_sort_criteria[] = { */ #define ngx_sizeof_ssz(_s) (sizeof(_s) - 1) +/** + * Compute the length of a statically allocated array + */ +#define DIM(x) (sizeof(x)/sizeof(*(x))) /** * Copy a static zero-terminated string. Useful to output template @@ -552,16 +556,20 @@ make_content_buf( off_t length; size_t len, root, copy, allocated; - u_char *filename, *last, scale; + int64_t multiplier; + u_char *filename, *last; ngx_tm_t tm; ngx_array_t entries; ngx_time_t *tp; - ngx_uint_t i; - ngx_int_t size; + ngx_uint_t i, j; ngx_str_t path; ngx_dir_t dir; ngx_buf_t *b; + static const char *sizes[] = { "EiB", "PiB", "TiB", "GiB", "MiB", "KiB", "B" }; + static const int64_t exbibyte = 1024LL * 1024LL * 1024LL * + 1024LL * 1024LL * 1024LL; + /* * NGX_DIR_MASK_LEN is lesser than NGX_HTTP_FANCYINDEX_PREALLOCATE */ @@ -982,41 +990,17 @@ make_content_buf( *b->last++ = '-'; } else { length = entry[i].size; + multiplier = exbibyte; - if (length > 1024 * 1024 * 1024 - 1) { - size = (ngx_int_t) (length / (1024 * 1024 * 1024)); - if ((length % (1024 * 1024 * 1024)) - > (1024 * 1024 * 1024 / 2 - 1)) - { - size++; - } - scale = 'G'; + for (j = 0; j < DIM(sizes) - 1 && length < multiplier; j++) + multiplier /= 1024; - } else if (length > 1024 * 1024 - 1) { - size = (ngx_int_t) (length / (1024 * 1024)); - if ((length % (1024 * 1024)) > (1024 * 1024 / 2 - 1)) { - size++; - } - scale = 'M'; - - } else if (length > 9999) { - size = (ngx_int_t) (length / 1024); - if (length % 1024 > 511) { - size++; - } - scale = 'K'; - - } else { - size = (ngx_int_t) length; - scale = '\0'; - } - - if (scale) { - b->last = ngx_sprintf(b->last, "%6i%c", size, scale); - - } else { - b->last = ngx_sprintf(b->last, " %6i", size); - } + /* If we are showing the filesize in bytes, do not show a decimal */ + if (j == DIM(sizes) - 1) + b->last = ngx_sprintf(b->last, "%O %s", length, sizes[j]); + else + b->last = ngx_sprintf(b->last, "%.1f %s", + (float) length / multiplier, sizes[j]); } } @@ -1245,7 +1229,7 @@ ngx_http_fancyindex_cmp_entries_size_desc(const void *one, const void *two) ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - return (int) (second->size - first->size); + return (first->size > second->size) - (first->size < second->size); } @@ -1275,7 +1259,7 @@ ngx_http_fancyindex_cmp_entries_size_asc(const void *one, const void *two) ngx_http_fancyindex_entry_t *first = (ngx_http_fancyindex_entry_t *) one; ngx_http_fancyindex_entry_t *second = (ngx_http_fancyindex_entry_t *) two; - return (int) (first->size - second->size); + return (first->size > second->size) - (first->size < second->size); } diff --git a/debian/modules/http-fancyindex/t/03-exact_size_off.test b/debian/modules/http-fancyindex/t/03-exact_size_off.test new file mode 100644 index 0000000..cdc61ec --- /dev/null +++ b/debian/modules/http-fancyindex/t/03-exact_size_off.test @@ -0,0 +1,8 @@ +#! /bin/bash +cat <<--- +We test if the output from using "fancyindex_exact_size off" looks sane +-- +nginx_start 'fancyindex_exact_size off;' +content=$(fetch) +grep -e '[1-9]\.[0-9] KiB' <<< "${content}" +grep -E '[0-9]+ B' <<< "${content}" diff --git a/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test b/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test new file mode 100644 index 0000000..d9c5a40 --- /dev/null +++ b/debian/modules/http-fancyindex/t/bug61-empty-file-segfault.test @@ -0,0 +1,16 @@ +#! /bin/bash +cat <<--- +Bug #61: Listing a directory with an empty file crashes Nginx +https://github.com/aperezdc/ngx-fancyindex/issues/61 +-- + +# Prepare an empty directory with an empty file +mkdir -p "${TESTDIR}/bug61" +touch "${TESTDIR}/bug61/bug61.txt" + +nginx_start 'fancyindex_exact_size off;' +content=$(fetch /bug61/) +test -n "${content}" || fail "Empty response" +echo "Response:" +echo "${content}" +nginx_is_running || fail "Nginx died" diff --git a/debian/modules/http-fancyindex/t/run b/debian/modules/http-fancyindex/t/run index 2001bff..dda4c59 100755 --- a/debian/modules/http-fancyindex/t/run +++ b/debian/modules/http-fancyindex/t/run @@ -26,7 +26,7 @@ readonly dynamic declare -a t_pass=( ) declare -a t_fail=( ) -for t in "$T"/*.test ; do +for t in `ls "$T"/*.test | sort -R` ; do name="t/${t##*/}" name=${name%.test} printf "${name} ... " diff --git a/debian/modules/http-fancyindex/template.h b/debian/modules/http-fancyindex/template.h index 4881ac7..e08ba01 100644 --- a/debian/modules/http-fancyindex/template.h +++ b/debian/modules/http-fancyindex/template.h @@ -1,12 +1,10 @@ /* Automagically generated, do not edit! */ static const u_char t01_head1[] = "" -"" -"\n" -"" -"\n" +"" +"" "" -"" -"" +"" +"" " diff --git a/html/index.html b/html/index.html index 2ca3b95..e8f5622 100644 --- a/html/index.html +++ b/html/index.html @@ -3,11 +3,9 @@ Welcome to nginx! diff --git a/src/core/nginx.h b/src/core/nginx.h index 7b873a1..329b603 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1020002 -#define NGINX_VERSION "1.20.2" +#define nginx_version 1022000 +#define NGINX_VERSION "1.22.0" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h index 4b66562..fdcd0cd 100644 --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -90,9 +90,6 @@ struct ngx_output_chain_ctx_s { #if (NGX_HAVE_FILE_AIO || NGX_COMPAT) ngx_output_chain_aio_pt aio_handler; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*aio_preload)(ngx_buf_t *file); -#endif #endif #if (NGX_THREADS || NGX_COMPAT) diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index 8339e2b..fe729a7 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -495,21 +495,24 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) return NGX_ERROR; } - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (const void *) &reuseaddr, sizeof(int)) - == -1) - { - ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEADDR) %V failed", - &ls[i].addr_text); + if (ls[i].type != SOCK_DGRAM || !ngx_test_config) { - if (ngx_close_socket(s) == -1) { + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) + == -1) + { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - ngx_close_socket_n " %V failed", + "setsockopt(SO_REUSEADDR) %V failed", &ls[i].addr_text); - } - return NGX_ERROR; + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, + ngx_close_socket_n " %V failed", + &ls[i].addr_text); + } + + return NGX_ERROR; + } } #if (NGX_HAVE_REUSEPORT) diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h index 4716da4..8cc1475 100644 --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -185,7 +185,7 @@ struct ngx_connection_s { unsigned need_last_buf:1; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) unsigned busy_count:2; #endif diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index d9c157c..8215c27 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -274,6 +274,10 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts) } for (n = 0; n < nelts; n++) { + if (names[n].key.data == NULL) { + continue; + } + if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, diff --git a/src/core/ngx_module.h b/src/core/ngx_module.h index 8cf3210..6fb4554 100644 --- a/src/core/ngx_module.h +++ b/src/core/ngx_module.h @@ -41,7 +41,7 @@ #define NGX_MODULE_SIGNATURE_3 "0" #endif -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) +#if (NGX_HAVE_SENDFILE_NODISKIO || NGX_COMPAT) #define NGX_MODULE_SIGNATURE_4 "1" #else #define NGX_MODULE_SIGNATURE_4 "0" diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c index 5c3dbe8..8570742 100644 --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -29,10 +29,6 @@ static ngx_inline ngx_int_t ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); -#if (NGX_HAVE_AIO_SENDFILE) -static ngx_int_t ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, - ngx_file_t *file); -#endif static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, @@ -260,10 +256,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } #endif - if (buf->in_file && buf->file->directio) { - return 0; - } - sendfile = ctx->sendfile; #if (NGX_SENDFILE_LIMIT) @@ -272,6 +264,19 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) sendfile = 0; } +#endif + +#if !(NGX_HAVE_SENDFILE_NODISKIO) + + /* + * With DIRECTIO, disable sendfile() unless sendfile(SF_NOCACHE) + * is available. + */ + + if (buf->in_file && buf->file->directio) { + sendfile = 0; + } + #endif if (!sendfile) { @@ -283,12 +288,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) buf->in_file = 0; } -#if (NGX_HAVE_AIO_SENDFILE) - if (ctx->aio_preload && buf->in_file) { - (void) ngx_output_chain_aio_setup(ctx, buf->file); - } -#endif - if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { return 0; } @@ -301,28 +300,6 @@ ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) } -#if (NGX_HAVE_AIO_SENDFILE) - -static ngx_int_t -ngx_output_chain_aio_setup(ngx_output_chain_ctx_t *ctx, ngx_file_t *file) -{ - ngx_event_aio_t *aio; - - if (file->aio == NULL && ngx_file_aio_init(file, ctx->pool) != NGX_OK) { - return NGX_ERROR; - } - - aio = file->aio; - - aio->data = ctx->filter_ctx; - aio->preload_handler = ctx->aio_preload; - - return NGX_OK; -} - -#endif - - static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in) @@ -803,6 +780,10 @@ ngx_chain_writer(void *data, ngx_chain_t *in) return NGX_ERROR; } + if (chain && c->write->ready) { + ngx_post_event(c->write, &ngx_posted_next_events); + } + for (cl = ctx->out; cl && cl != chain; /* void */) { ln = cl; cl = cl->next; diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h index 97f0e3e..e8c3582 100644 --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -47,6 +47,9 @@ struct ngx_rbtree_s { (tree)->sentinel = s; \ (tree)->insert = i +#define ngx_rbtree_data(node, type, link) \ + (type *) ((u_char *) (node) - offsetof(type, link)) + void ngx_rbtree_insert(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); void ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node); diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c index 52169f6..bebf3b6 100644 --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -10,15 +10,22 @@ typedef struct { - ngx_flag_t pcre_jit; + ngx_flag_t pcre_jit; + ngx_list_t *studies; } ngx_regex_conf_t; +static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool); +static ngx_inline void ngx_regex_malloc_done(void); + +#if (NGX_PCRE2) +static void * ngx_libc_cdecl ngx_regex_malloc(size_t size, void *data); +static void ngx_libc_cdecl ngx_regex_free(void *p, void *data); +#else static void * ngx_libc_cdecl ngx_regex_malloc(size_t size); static void ngx_libc_cdecl ngx_regex_free(void *p); -#if (NGX_HAVE_PCRE_JIT) -static void ngx_pcre_free_studies(void *data); #endif +static void ngx_regex_cleanup(void *data); static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle); @@ -65,32 +72,197 @@ ngx_module_t ngx_regex_module = { }; -static ngx_pool_t *ngx_pcre_pool; -static ngx_list_t *ngx_pcre_studies; +static ngx_pool_t *ngx_regex_pool; +static ngx_list_t *ngx_regex_studies; +static ngx_uint_t ngx_regex_direct_alloc; + +#if (NGX_PCRE2) +static pcre2_compile_context *ngx_regex_compile_context; +static pcre2_match_data *ngx_regex_match_data; +static ngx_uint_t ngx_regex_match_data_size; +#endif void ngx_regex_init(void) { +#if !(NGX_PCRE2) pcre_malloc = ngx_regex_malloc; pcre_free = ngx_regex_free; +#endif } static ngx_inline void ngx_regex_malloc_init(ngx_pool_t *pool) { - ngx_pcre_pool = pool; + ngx_regex_pool = pool; + ngx_regex_direct_alloc = (pool == NULL) ? 1 : 0; } static ngx_inline void ngx_regex_malloc_done(void) { - ngx_pcre_pool = NULL; + ngx_regex_pool = NULL; + ngx_regex_direct_alloc = 0; } +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_compile(ngx_regex_compile_t *rc) +{ + int n, errcode; + char *p; + u_char errstr[128]; + size_t erroff; + uint32_t options; + pcre2_code *re; + ngx_regex_elt_t *elt; + pcre2_general_context *gctx; + pcre2_compile_context *cctx; + + if (ngx_regex_compile_context == NULL) { + /* + * Allocate a compile context if not yet allocated. This uses + * direct allocations from heap, so the result can be cached + * even at runtime. + */ + + ngx_regex_malloc_init(NULL); + + gctx = pcre2_general_context_create(ngx_regex_malloc, ngx_regex_free, + NULL); + if (gctx == NULL) { + ngx_regex_malloc_done(); + goto nomem; + } + + cctx = pcre2_compile_context_create(gctx); + if (cctx == NULL) { + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + goto nomem; + } + + ngx_regex_compile_context = cctx; + + pcre2_general_context_free(gctx); + ngx_regex_malloc_done(); + } + + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE2_CASELESS; + } + + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE2_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + + ngx_regex_malloc_init(rc->pool); + + re = pcre2_compile(rc->pattern.data, rc->pattern.len, options, + &errcode, &erroff, ngx_regex_compile_context); + + /* ensure that there is no current pool */ + ngx_regex_malloc_done(); + + if (re == NULL) { + pcre2_get_error_message(errcode, errstr, 128); + + if ((size_t) erroff == rc->pattern.len) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\"", + errstr, &rc->pattern) + - rc->err.data; + + } else { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "pcre2_compile() failed: %s in \"%V\" at \"%s\"", + errstr, &rc->pattern, rc->pattern.data + erroff) + - rc->err.data; + } + + return NGX_ERROR; + } + + rc->regex = re; + + /* do not study at runtime */ + + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); + if (elt == NULL) { + goto nomem; + } + + elt->regex = rc->regex; + elt->name = rc->pattern.data; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &rc->captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_CAPTURECOUNT) failed: %d"; + goto failed; + } + + if (rc->captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMECOUNT, &rc->named_captures); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMECOUNT) failed: %d"; + goto failed; + } + + if (rc->named_captures == 0) { + return NGX_OK; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMEENTRYSIZE, &rc->name_size); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMEENTRYSIZE) failed: %d"; + goto failed; + } + + n = pcre2_pattern_info(re, PCRE2_INFO_NAMETABLE, &rc->names); + if (n < 0) { + p = "pcre2_pattern_info(\"%V\", PCRE2_INFO_NAMETABLE) failed: %d"; + goto failed; + } + + return NGX_OK; + +failed: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n) + - rc->err.data; + return NGX_ERROR; + +nomem: + + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: no memory", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; +} + +#else + ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc) { @@ -98,11 +270,30 @@ ngx_regex_compile(ngx_regex_compile_t *rc) char *p; pcre *re; const char *errstr; + ngx_uint_t options; ngx_regex_elt_t *elt; + options = 0; + + if (rc->options & NGX_REGEX_CASELESS) { + options |= PCRE_CASELESS; + } + + if (rc->options & NGX_REGEX_MULTILINE) { + options |= PCRE_MULTILINE; + } + + if (rc->options & ~(NGX_REGEX_CASELESS|NGX_REGEX_MULTILINE)) { + rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, + "regex \"%V\" compilation failed: invalid options", + &rc->pattern) + - rc->err.data; + return NGX_ERROR; + } + ngx_regex_malloc_init(rc->pool); - re = pcre_compile((const char *) rc->pattern.data, (int) rc->options, + re = pcre_compile((const char *) rc->pattern.data, (int) options, &errstr, &erroff, NULL); /* ensure that there is no current pool */ @@ -113,13 +304,13 @@ ngx_regex_compile(ngx_regex_compile_t *rc) rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\"", errstr, &rc->pattern) - - rc->err.data; + - rc->err.data; } else { rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, "pcre_compile() failed: %s in \"%V\" at \"%s\"", errstr, &rc->pattern, rc->pattern.data + erroff) - - rc->err.data; + - rc->err.data; } return NGX_ERROR; @@ -134,8 +325,8 @@ ngx_regex_compile(ngx_regex_compile_t *rc) /* do not study at runtime */ - if (ngx_pcre_studies != NULL) { - elt = ngx_list_push(ngx_pcre_studies); + if (ngx_regex_studies != NULL) { + elt = ngx_list_push(ngx_regex_studies); if (elt == NULL) { goto nomem; } @@ -193,6 +384,83 @@ nomem: return NGX_ERROR; } +#endif + + +#if (NGX_PCRE2) + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + size_t *ov; + ngx_int_t rc; + ngx_uint_t n, i; + + /* + * The pcre2_match() function might allocate memory for backtracking + * frames, typical allocations are from 40k and above. So the allocator + * is configured to do direct allocations from heap during matching. + */ + + ngx_regex_malloc_init(NULL); + + if (ngx_regex_match_data == NULL + || size > ngx_regex_match_data_size) + { + /* + * Allocate a match data if not yet allocated or smaller than + * needed. + */ + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + } + + ngx_regex_match_data_size = size; + ngx_regex_match_data = pcre2_match_data_create(size / 3, NULL); + + if (ngx_regex_match_data == NULL) { + rc = PCRE2_ERROR_NOMEMORY; + goto failed; + } + } + + rc = pcre2_match(re, s->data, s->len, 0, 0, ngx_regex_match_data, NULL); + + if (rc < 0) { + goto failed; + } + + n = pcre2_get_ovector_count(ngx_regex_match_data); + ov = pcre2_get_ovector_pointer(ngx_regex_match_data); + + if (n > size / 3) { + n = size / 3; + } + + for (i = 0; i < n; i++) { + captures[i * 2] = ov[i * 2]; + captures[i * 2 + 1] = ov[i * 2 + 1]; + } + +failed: + + ngx_regex_malloc_done(); + + return rc; +} + +#else + +ngx_int_t +ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_uint_t size) +{ + return pcre_exec(re->code, re->extra, (const char *) s->data, s->len, + 0, 0, captures, size); +} + +#endif + ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) @@ -227,14 +495,40 @@ ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) } +#if (NGX_PCRE2) + +static void * ngx_libc_cdecl +ngx_regex_malloc(size_t size, void *data) +{ + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); + } + + if (ngx_regex_direct_alloc) { + return ngx_alloc(size, ngx_cycle->log); + } + + return NULL; +} + + +static void ngx_libc_cdecl +ngx_regex_free(void *p, void *data) +{ + if (ngx_regex_direct_alloc) { + ngx_free(p); + } + + return; +} + +#else + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { - ngx_pool_t *pool; - pool = ngx_pcre_pool; - - if (pool) { - return ngx_palloc(pool, size); + if (ngx_regex_pool) { + return ngx_palloc(ngx_regex_pool, size); } return NULL; @@ -247,19 +541,20 @@ ngx_regex_free(void *p) return; } +#endif -#if (NGX_HAVE_PCRE_JIT) static void -ngx_pcre_free_studies(void *data) +ngx_regex_cleanup(void *data) { - ngx_list_t *studies = data; +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + ngx_regex_conf_t *rcf = data; ngx_uint_t i; ngx_list_part_t *part; ngx_regex_elt_t *elts; - part = &studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -274,56 +569,83 @@ ngx_pcre_free_studies(void *data) i = 0; } + /* + * The PCRE JIT compiler uses mmap for its executable codes, so we + * have to explicitly call the pcre_free_study() function to free + * this memory. In PCRE2, we call the pcre2_code_free() function + * for the same reason. + */ + +#if (NGX_PCRE2) + pcre2_code_free(elts[i].regex); +#else if (elts[i].regex->extra != NULL) { pcre_free_study(elts[i].regex->extra); } +#endif + } +#endif + + /* + * On configuration parsing errors ngx_regex_module_init() will not + * be called. Make sure ngx_regex_studies is properly cleared anyway. + */ + + ngx_regex_studies = NULL; + +#if (NGX_PCRE2) + + /* + * Free compile context and match data. If needed at runtime by + * the new cycle, these will be re-allocated. + */ + + if (ngx_regex_compile_context) { + pcre2_compile_context_free(ngx_regex_compile_context); + ngx_regex_compile_context = NULL; + } + + if (ngx_regex_match_data) { + pcre2_match_data_free(ngx_regex_match_data); + ngx_regex_match_data = NULL; + ngx_regex_match_data_size = 0; } -} #endif +} static ngx_int_t ngx_regex_module_init(ngx_cycle_t *cycle) { - int opt; - const char *errstr; - ngx_uint_t i; - ngx_list_part_t *part; - ngx_regex_elt_t *elts; + int opt; +#if !(NGX_PCRE2) + const char *errstr; +#endif + ngx_uint_t i; + ngx_list_part_t *part; + ngx_regex_elt_t *elts; + ngx_regex_conf_t *rcf; opt = 0; -#if (NGX_HAVE_PCRE_JIT) - { - ngx_regex_conf_t *rcf; - ngx_pool_cleanup_t *cln; - rcf = (ngx_regex_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_regex_module); +#if (NGX_PCRE2 || NGX_HAVE_PCRE_JIT) + if (rcf->pcre_jit) { +#if (NGX_PCRE2) + opt = 1; +#else opt = PCRE_STUDY_JIT_COMPILE; - - /* - * The PCRE JIT compiler uses mmap for its executable codes, so we - * have to explicitly call the pcre_free_study() function to free - * this memory. - */ - - cln = ngx_pool_cleanup_add(cycle->pool, 0); - if (cln == NULL) { - return NGX_ERROR; - } - - cln->handler = ngx_pcre_free_studies; - cln->data = ngx_pcre_studies; - } +#endif } + #endif ngx_regex_malloc_init(cycle->pool); - part = &ngx_pcre_studies->part; + part = &rcf->studies->part; elts = part->elts; for (i = 0; /* void */ ; i++) { @@ -338,6 +660,23 @@ ngx_regex_module_init(ngx_cycle_t *cycle) i = 0; } +#if (NGX_PCRE2) + + if (opt) { + int n; + + n = pcre2_jit_compile(elts[i].regex, PCRE2_JIT_COMPLETE); + + if (n != 0) { + ngx_log_error(NGX_LOG_INFO, cycle->log, 0, + "pcre2_jit_compile() failed: %d in \"%s\", " + "ignored", + n, elts[i].name); + } + } + +#else + elts[i].regex->extra = pcre_study(elts[i].regex->code, opt, &errstr); if (errstr != NULL) { @@ -360,12 +699,16 @@ ngx_regex_module_init(ngx_cycle_t *cycle) elts[i].name); } } +#endif #endif } ngx_regex_malloc_done(); - ngx_pcre_studies = NULL; + ngx_regex_studies = NULL; +#if (NGX_PCRE2) + ngx_regex_compile_context = NULL; +#endif return NGX_OK; } @@ -374,7 +717,8 @@ ngx_regex_module_init(ngx_cycle_t *cycle) static void * ngx_regex_create_conf(ngx_cycle_t *cycle) { - ngx_regex_conf_t *rcf; + ngx_regex_conf_t *rcf; + ngx_pool_cleanup_t *cln; rcf = ngx_pcalloc(cycle->pool, sizeof(ngx_regex_conf_t)); if (rcf == NULL) { @@ -383,11 +727,21 @@ ngx_regex_create_conf(ngx_cycle_t *cycle) rcf->pcre_jit = NGX_CONF_UNSET; - ngx_pcre_studies = ngx_list_create(cycle->pool, 8, sizeof(ngx_regex_elt_t)); - if (ngx_pcre_studies == NULL) { + cln = ngx_pool_cleanup_add(cycle->pool, 0); + if (cln == NULL) { 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; + } + + ngx_regex_studies = rcf->studies; + return rcf; } @@ -412,7 +766,21 @@ ngx_regex_pcre_jit(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; } -#if (NGX_HAVE_PCRE_JIT) +#if (NGX_PCRE2) + { + int r; + uint32_t jit; + + jit = 0; + r = pcre2_config(PCRE2_CONFIG_JIT, &jit); + + if (r != 0 || jit != 1) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "PCRE2 library does not support JIT"); + *fp = 0; + } + } +#elif (NGX_HAVE_PCRE_JIT) { int jit, r; diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h index 680486c..182373a 100644 --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -12,24 +12,38 @@ #include #include + +#if (NGX_PCRE2) + +#define PCRE2_CODE_UNIT_WIDTH 8 +#include + +#define NGX_REGEX_NO_MATCHED PCRE2_ERROR_NOMATCH /* -1 */ + +typedef pcre2_code ngx_regex_t; + +#else + #include - -#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ - -#define NGX_REGEX_CASELESS PCRE_CASELESS - +#define NGX_REGEX_NO_MATCHED PCRE_ERROR_NOMATCH /* -1 */ typedef struct { pcre *code; pcre_extra *extra; } ngx_regex_t; +#endif + + +#define NGX_REGEX_CASELESS 0x00000001 +#define NGX_REGEX_MULTILINE 0x00000002 + typedef struct { ngx_str_t pattern; ngx_pool_t *pool; - ngx_int_t options; + ngx_uint_t options; ngx_regex_t *regex; int captures; @@ -49,10 +63,14 @@ typedef struct { void ngx_regex_init(void); ngx_int_t ngx_regex_compile(ngx_regex_compile_t *rc); -#define ngx_regex_exec(re, s, captures, size) \ - pcre_exec(re->code, re->extra, (const char *) (s)->data, (s)->len, 0, 0, \ - captures, size) -#define ngx_regex_exec_n "pcre_exec()" +ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, + ngx_uint_t size); + +#if (NGX_PCRE2) +#define ngx_regex_exec_n "pcre2_match()" +#else +#define ngx_regex_exec_n "pcre_exec()" +#endif ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index 58d5f3e..6d129e5 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -51,9 +51,7 @@ typedef struct { } ngx_resolver_an_t; -#define ngx_resolver_node(n) \ - (ngx_resolver_node_t *) \ - ((u_char *) (n) - offsetof(ngx_resolver_node_t, node)) +#define ngx_resolver_node(n) ngx_rbtree_data(n, ngx_resolver_node_t, node) static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec); diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index ed2b0f8..e7da8a8 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -89,22 +89,10 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) void ngx_rwlock_unlock(ngx_atomic_t *lock) { - ngx_atomic_uint_t readers; - - readers = *lock; - - if (readers == NGX_RWLOCK_WLOCK) { + if (*lock == NGX_RWLOCK_WLOCK) { (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); - return; - } - - for ( ;; ) { - - if (ngx_atomic_cmp_set(lock, readers, readers - 1)) { - return; - } - - readers = *lock; + } else { + (void) ngx_atomic_fetch_add(lock, -1); } } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 93f32ea..98f270a 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1493,19 +1493,32 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) uint32_t *escape; static u_char hex[] = "0123456789ABCDEF"; - /* " ", "#", "%", "?", %00-%1F, %7F-%FF */ + /* + * Per RFC 3986 only the following chars are allowed in URIs unescaped: + * + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + * / "*" / "+" / "," / ";" / "=" + * + * And "%" can appear as a part of escaping itself. The following + * characters are not allowed and need to be escaped: %00-%1F, %7F-%FF, + * " ", """, "<", ">", "\", "^", "`", "{", "|", "}". + */ + + /* " ", "#", "%", "?", not allowed */ static uint32_t uri[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x80000029, /* 1000 0000 0000 0000 0000 0000 0010 1001 */ + 0xd000002d, /* 1101 0000 0000 0000 0000 0000 0010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1513,19 +1526,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", "%", "&", "+", "?", %00-%1F, %7F-%FF */ + /* " ", "#", "%", "&", "+", ";", "?", not allowed */ static uint32_t args[] = { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x88000869, /* 1000 1000 0000 0000 0000 1000 0110 1001 */ + 0xd800086d, /* 1101 1000 0000 0000 0000 1000 0110 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1553,19 +1566,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", "#", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", "#", """, "%", "'", not allowed */ 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 */ + 0x500000ad, /* 0101 0000 0000 0000 0000 0000 1010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1573,19 +1586,19 @@ ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", """, "%", "'", %00-%1F, %7F-%FF */ + /* " ", """, "'", not allowed */ 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 */ + 0x50000085, /* 0101 0000 0000 0000 0000 0000 1000 0101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x50000000, /* 0101 0000 0000 0000 0000 0000 0000 0000 */ /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xd8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c index 7964b00..16788c9 100644 --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -200,10 +200,6 @@ ngx_monotonic_time(time_t sec, ngx_uint_t msec) #if defined(CLOCK_MONOTONIC_FAST) clock_gettime(CLOCK_MONOTONIC_FAST, &ts); - -#elif defined(CLOCK_MONOTONIC_COARSE) - clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); - #else clock_gettime(CLOCK_MONOTONIC, &ts); #endif diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c index 7777d04..47229b5 100644 --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -55,6 +55,7 @@ ngx_uint_t ngx_accept_events; ngx_uint_t ngx_accept_mutex_held; ngx_msec_t ngx_accept_mutex_delay; ngx_int_t ngx_accept_disabled; +ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) @@ -441,20 +442,23 @@ ngx_event_init_conf(ngx_cycle_t *cycle, void *conf) #if (NGX_HAVE_REUSEPORT) - ls = cycle->listening.elts; - for (i = 0; i < cycle->listening.nelts; i++) { - - if (!ls[i].reuseport || ls[i].worker != 0) { - continue; - } - - if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { - return NGX_CONF_ERROR; - } - - /* cloning may change cycle->listening.elts */ + if (!ngx_test_config) { ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + + if (!ls[i].reuseport || ls[i].worker != 0) { + continue; + } + + if (ngx_clone_listening(cycle, &ls[i]) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* cloning may change cycle->listening.elts */ + + ls = cycle->listening.elts; + } } #endif @@ -641,6 +645,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) #endif + ngx_use_exclusive_accept = 0; + ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_next_events); ngx_queue_init(&ngx_posted_events); @@ -886,6 +892,8 @@ ngx_event_process_init(ngx_cycle_t *cycle) if ((ngx_event_flags & NGX_USE_EPOLL_EVENT) && ccf->worker_processes > 1) { + ngx_use_exclusive_accept = 1; + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) == NGX_ERROR) { diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h index 97f9673..548c906 100644 --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -147,10 +147,6 @@ struct ngx_event_aio_s { ngx_fd_t fd; -#if (NGX_HAVE_AIO_SENDFILE || NGX_COMPAT) - ssize_t (*preload_handler)(ngx_buf_t *file); -#endif - #if (NGX_HAVE_EVENTFD) int64_t res; #endif @@ -466,6 +462,7 @@ extern ngx_uint_t ngx_accept_events; extern ngx_uint_t ngx_accept_mutex_held; extern ngx_msec_t ngx_accept_mutex_delay; extern ngx_int_t ngx_accept_disabled; +extern ngx_uint_t ngx_use_exclusive_accept; #if (NGX_STAT_STUB) diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c index b05666c..2703879 100644 --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -11,6 +11,9 @@ static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all); +#if (NGX_HAVE_EPOLLEXCLUSIVE) +static void ngx_reorder_accept_events(ngx_listening_t *ls); +#endif static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -314,6 +317,10 @@ ngx_event_accept(ngx_event_t *ev) } } while (ev->available); + +#if (NGX_HAVE_EPOLLEXCLUSIVE) + ngx_reorder_accept_events(ls); +#endif } @@ -420,6 +427,57 @@ ngx_disable_accept_events(ngx_cycle_t *cycle, ngx_uint_t all) } +#if (NGX_HAVE_EPOLLEXCLUSIVE) + +static void +ngx_reorder_accept_events(ngx_listening_t *ls) +{ + ngx_connection_t *c; + + /* + * Linux with EPOLLEXCLUSIVE usually notifies only the process which + * was first to add the listening socket to the epoll instance. As + * a result most of the connections are handled by the first worker + * process. To fix this, we re-add the socket periodically, so other + * workers will get a chance to accept connections. + */ + + if (!ngx_use_exclusive_accept) { + return; + } + +#if (NGX_HAVE_REUSEPORT) + + if (ls->reuseport) { + return; + } + +#endif + + c = ls->connection; + + if (c->requests++ % 16 != 0 + && ngx_accept_disabled <= 0) + { + return; + } + + if (ngx_del_event(c->read, NGX_READ_EVENT, NGX_DISABLE_EVENT) + == NGX_ERROR) + { + return; + } + + if (ngx_add_event(c->read, NGX_READ_EVENT, NGX_EXCLUSIVE_EVENT) + == NGX_ERROR) + { + return; + } +} + +#endif + + static void ngx_close_accepted_connection(ngx_connection_t *c) { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index ce2a566..1e6fc96 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -47,6 +47,8 @@ static void ngx_ssl_write_handler(ngx_event_t *wev); static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size); #endif +static ssize_t ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, + size_t size); static void ngx_ssl_read_handler(ngx_event_t *rev); static void ngx_ssl_shutdown_handler(ngx_event_t *ev); static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, @@ -299,11 +301,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); #endif -#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING - /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */ - SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING); -#endif - #ifdef SSL_OP_SSLEAY_080_CLIENT_DH_BUG SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG); #endif @@ -863,11 +860,6 @@ ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - /* a temporary 512-bit RSA key is required for export versions of MSIE */ - SSL_CTX_set_tmp_rsa_callback(ssl->ctx, ngx_ssl_rsa512_key_callback); -#endif - return NGX_OK; } @@ -1120,32 +1112,6 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret) } -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) - -RSA * -ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, - int key_length) -{ - static RSA *key; - - if (key_length != 512) { - return NULL; - } - -#ifndef OPENSSL_NO_DEPRECATED - - if (key == NULL) { - key = RSA_generate_key(512, RSA_F4, NULL, NULL); - } - -#endif - - return key; -} - -#endif - - ngx_array_t * ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) { @@ -1417,6 +1383,9 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) if (SSL_CTX_set0_tmp_dh_pkey(ssl->ctx, dh) != 1) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set0_tmp_dh_pkey(\%s\") failed", file->data); +#if (OPENSSL_VERSION_NUMBER >= 0x3000001fL) + EVP_PKEY_free(dh); +#endif BIO_free(bio); return NGX_ERROR; } @@ -1798,6 +1767,16 @@ ngx_ssl_handshake(ngx_connection_t *c) #endif #endif +#endif + +#ifdef BIO_get_ktls_send + + if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "BIO_get_ktls_send(): 1"); + c->ssl->sendfile = 1; + } + #endif rc = ngx_ssl_ocsp_validate(c); @@ -1935,6 +1914,16 @@ ngx_ssl_try_early_data(ngx_connection_t *c) c->read->ready = 1; c->write->ready = 1; +#ifdef BIO_get_ktls_send + + if (BIO_get_ktls_send(SSL_get_wbio(c->ssl->connection)) == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "BIO_get_ktls_send(): 1"); + c->ssl->sendfile = 1; + } + +#endif + rc = ngx_ssl_ocsp_validate(c); if (rc == NGX_ERROR) { @@ -2538,10 +2527,11 @@ ngx_ssl_write_handler(ngx_event_t *wev) ngx_chain_t * ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int n; - ngx_uint_t flush; - ssize_t send, size; - ngx_buf_t *buf; + int n; + ngx_uint_t flush; + ssize_t send, size, file_size; + ngx_buf_t *buf; + ngx_chain_t *cl; if (!c->ssl->buffer) { @@ -2615,6 +2605,11 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) continue; } + if (in->buf->in_file && c->ssl->sendfile) { + flush = 1; + break; + } + size = in->buf->last - in->buf->pos; if (size > buf->end - buf->last) { @@ -2646,8 +2641,35 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) size = buf->last - buf->pos; if (size == 0) { + + if (in && in->buf->in_file && send < limit) { + + /* coalesce the neighbouring file bufs */ + + cl = in; + file_size = (size_t) ngx_chain_coalesce_file(&cl, limit - send); + + n = ngx_ssl_sendfile(c, in->buf, file_size); + + if (n == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (n == NGX_AGAIN) { + break; + } + + in = ngx_chain_update_sent(in, n); + + send += n; + flush = 0; + + continue; + } + buf->flush = 0; c->buffered &= ~NGX_SSL_BUFFERED; + return in; } @@ -2672,7 +2694,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) buf->pos = buf->start; buf->last = buf->start; - if (in == NULL || send == limit) { + if (in == NULL || send >= limit) { break; } } @@ -2803,7 +2825,7 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) #ifdef SSL_READ_EARLY_DATA_SUCCESS -ssize_t +static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) { int n, sslerr; @@ -2918,6 +2940,183 @@ ngx_ssl_write_early(ngx_connection_t *c, u_char *data, size_t size) #endif +static ssize_t +ngx_ssl_sendfile(ngx_connection_t *c, ngx_buf_t *file, size_t size) +{ +#ifdef BIO_get_ktls_send + + int sslerr, flags; + ssize_t n; + ngx_err_t err; + + ngx_ssl_clear_error(c->log); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL to sendfile: @%O %uz", + file->file_pos, size); + + ngx_set_errno(0); + +#if (NGX_HAVE_SENDFILE_NODISKIO) + + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + +#else + flags = 0; +#endif + + 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); + + if (n > 0) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + +#if (NGX_HAVE_SENDFILE_NODISKIO) + c->busy_count = 0; +#endif + + c->sent += n; + + return n; + } + + if (n == 0) { + + /* + * if sendfile returns zero, then someone has truncated the file, + * so the offset became beyond the end of the file + */ + + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "SSL_sendfile() reported that \"%s\" was truncated at %O", + file->file->name.data, file->file_pos); + + return NGX_ERROR; + } + + sslerr = SSL_get_error(c->ssl->connection, n); + + if (sslerr == SSL_ERROR_ZERO_RETURN) { + + /* + * OpenSSL fails to return SSL_ERROR_SYSCALL if an error + * happens during writing after close_notify alert from the + * peer, and returns SSL_ERROR_ZERO_RETURN instead + */ + + sslerr = SSL_ERROR_SYSCALL; + } + + if (sslerr == SSL_ERROR_SSL + && ERR_GET_REASON(ERR_peek_error()) == SSL_R_UNINITIALIZED + && ngx_errno != 0) + { + /* + * OpenSSL fails to return SSL_ERROR_SYSCALL if an error + * happens in sendfile(), and returns SSL_ERROR_SSL with + * SSL_R_UNINITIALIZED reason instead + */ + + sslerr = SSL_ERROR_SYSCALL; + } + + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); + + if (sslerr == SSL_ERROR_WANT_WRITE) { + + if (c->ssl->saved_read_handler) { + + c->read->handler = c->ssl->saved_read_handler; + c->ssl->saved_read_handler = NULL; + c->read->ready = 1; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + ngx_post_event(c->read, &ngx_posted_events); + } + +#if (NGX_HAVE_SENDFILE_NODISKIO) + + if (ngx_errno == EBUSY) { + c->busy_count++; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile() busy, count:%d", c->busy_count); + + if (c->write->posted) { + ngx_delete_posted_event(c->write); + } + + ngx_post_event(c->write, &ngx_posted_next_events); + } + +#endif + + c->write->ready = 0; + return NGX_AGAIN; + } + + if (sslerr == SSL_ERROR_WANT_READ) { + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL_sendfile: want read"); + + c->read->ready = 0; + + if (ngx_handle_read_event(c->read, 0) != NGX_OK) { + return NGX_ERROR; + } + + /* + * we do not set the timer because there is already + * the write event timer + */ + + if (c->ssl->saved_read_handler == NULL) { + c->ssl->saved_read_handler = c->read->handler; + c->read->handler = ngx_ssl_read_handler; + } + + return NGX_AGAIN; + } + + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + c->write->error = 1; + + ngx_ssl_connection_error(c, sslerr, err, "SSL_sendfile() failed"); + +#else + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "SSL_sendfile() not available"); +#endif + + return NGX_ERROR; +} + + static void ngx_ssl_read_handler(ngx_event_t *rev) { @@ -3169,6 +3368,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, #endif #ifdef SSL_R_CALLBACK_FAILED || n == SSL_R_CALLBACK_FAILED /* 234 */ +#endif +#ifdef SSL_R_NO_APPLICATION_PROTOCOL + || n == SSL_R_NO_APPLICATION_PROTOCOL /* 235 */ #endif || n == SSL_R_UNEXPECTED_MESSAGE /* 244 */ || n == SSL_R_UNEXPECTED_RECORD /* 245 */ @@ -4249,7 +4451,21 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, return -1; } - return (i == 0) ? 1 : 2 /* renew */; + /* renew if TLSv1.3 */ + +#ifdef TLS1_3_VERSION + if (SSL_version(ssl_conn) == TLS1_3_VERSION) { + return 2; + } +#endif + + /* renew if non-default key */ + + if (i != 0) { + return 2; + } + + return 1; } } @@ -4567,6 +4783,42 @@ ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_get_negotiated_group + + int nid; + + nid = SSL_get_negotiated_group(c->ssl->connection); + + if (nid != NID_undef) { + + if ((nid & TLSEXT_nid_unknown) == 0) { + s->len = ngx_strlen(OBJ_nid2sn(nid)); + s->data = (u_char *) OBJ_nid2sn(nid); + return NGX_OK; + } + + s->len = sizeof("0x0000") - 1; + + s->data = ngx_pnalloc(pool, s->len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(s->data, "0x%04xd", nid & 0xffff); + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { @@ -4734,6 +4986,36 @@ ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + + unsigned int len; + const unsigned char *data; + + SSL_get0_alpn_selected(c->ssl->connection, &data, &len); + + if (len > 0) { + + s->data = ngx_pnalloc(pool, len); + if (s->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(s->data, data, len); + s->len = len; + + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 81b87d7..c9e86d9 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -29,7 +29,6 @@ #include #endif #include -#include #include #include @@ -110,6 +109,7 @@ struct ngx_ssl_connection_s { unsigned handshake_rejected:1; unsigned renegotiation:1; unsigned buffer:1; + unsigned sendfile:1; unsigned no_wait_shutdown:1; unsigned no_send_shutdown:1; unsigned shutdown_without_free:1; @@ -208,10 +208,6 @@ 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); -#if (OPENSSL_VERSION_NUMBER < 0x10100001L && !defined LIBRESSL_VERSION_NUMBER) -RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, - int key_length); -#endif 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); @@ -260,6 +256,8 @@ ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_ciphers(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_curve(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_curves(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, @@ -270,6 +268,8 @@ ngx_int_t ngx_ssl_get_early_data(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_alpn_protocol(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); ngx_int_t ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c index 698b88f..35052bc 100644 --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -73,7 +73,7 @@ ngx_event_expire_timers(void) return; } - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "event timer del: %d: %M", @@ -113,7 +113,7 @@ ngx_event_no_timers_left(void) node; node = ngx_rbtree_next(&ngx_event_timer_rbtree, node)) { - ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer)); + ev = ngx_rbtree_data(node, ngx_event_t, timer); if (!ev->cancelable) { return NGX_AGAIN; diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c index ed9df34..0693319 100644 --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -16,7 +16,7 @@ typedef struct { ngx_http_complex_value_t *realm; - ngx_http_complex_value_t user_file; + ngx_http_complex_value_t *user_file; } ngx_http_auth_basic_loc_conf_t; @@ -107,7 +107,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); - if (alcf->realm == NULL || alcf->user_file.value.data == NULL) { + if (alcf->realm == NULL || alcf->user_file == NULL) { return NGX_DECLINED; } @@ -133,7 +133,7 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) { + if (ngx_http_complex_value(r, alcf->user_file, &user_file) != NGX_OK) { return NGX_ERROR; } @@ -357,6 +357,9 @@ ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf) return NULL; } + conf->realm = NGX_CONF_UNSET_PTR; + conf->user_file = NGX_CONF_UNSET_PTR; + return conf; } @@ -367,13 +370,8 @@ ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_auth_basic_loc_conf_t *prev = parent; ngx_http_auth_basic_loc_conf_t *conf = child; - if (conf->realm == NULL) { - conf->realm = prev->realm; - } - - if (conf->user_file.value.data == NULL) { - conf->user_file = prev->user_file; - } + ngx_conf_merge_ptr_value(conf->realm, prev->realm, NULL); + ngx_conf_merge_ptr_value(conf->user_file, prev->user_file, NULL); return NGX_CONF_OK; } @@ -406,17 +404,22 @@ ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; ngx_http_compile_complex_value_t ccv; - if (alcf->user_file.value.data) { + if (alcf->user_file != NGX_CONF_UNSET_PTR) { return "is duplicate"; } + alcf->user_file = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (alcf->user_file == NULL) { + return NGX_CONF_ERROR; + } + value = cf->args->elts; ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[1]; - ccv.complex_value = &alcf->user_file; + ccv.complex_value = alcf->user_file; ccv.zero = 1; ccv.conf_prefix = 1; diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c index 8b69e6f..0cc9ae1 100644 --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -1072,6 +1072,10 @@ ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found, static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r) { + u_char *p; + size_t len; + uintptr_t escape; + r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { return NGX_ERROR; @@ -1079,7 +1083,26 @@ ngx_http_dav_location(ngx_http_request_t *r) r->headers_out.location->hash = 1; ngx_str_set(&r->headers_out.location->key, "Location"); - r->headers_out.location->value = r->uri; + + escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI); + + if (escape) { + len = r->uri.len + escape; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + ngx_http_clear_location(r); + return NGX_ERROR; + } + + r->headers_out.location->value.len = len; + r->headers_out.location->value.data = p; + + ngx_escape_uri(p, r->uri.data, r->uri.len, NGX_ESCAPE_URI); + + } else { + r->headers_out.location->value = r->uri; + } return NGX_OK; } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 5191880..4a8dc33 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -2019,10 +2019,12 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r) break; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index 27a36e8..864fc4f 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -37,9 +37,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_grpc_loc_conf_t; @@ -426,16 +423,16 @@ static ngx_command_t ngx_http_grpc_commands[] = { { ngx_string("grpc_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate), + offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("grpc_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_grpc_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_grpc_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("grpc_ssl_password_file"), @@ -2180,6 +2177,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes) } ctx->rst = 1; + + continue; } if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { @@ -3181,10 +3180,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3290,10 +3289,10 @@ ngx_http_grpc_parse_fragment(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, ctx->field_rest -= size; if (ctx->field_huffman) { - if (ngx_http_v2_huff_decode(&ctx->field_state, p, size, - &ctx->field_end, - ctx->field_rest == 0, - r->connection->log) + if (ngx_http_huff_decode(&ctx->field_state, p, size, + &ctx->field_end, + ctx->field_rest == 0, + r->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, @@ -3385,7 +3384,7 @@ ngx_http_grpc_validate_header_name(ngx_http_request_t *r, ngx_str_t *s) return NGX_ERROR; } - if (ch == '\0' || ch == CR || ch == LF) { + if (ch <= 0x20 || ch == 0x7f) { return NGX_ERROR; } } @@ -3487,6 +3486,8 @@ ngx_http_grpc_parse_rst_stream(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx, return NGX_AGAIN; } + ctx->state = ngx_http_grpc_st_start; + return NGX_OK; } @@ -4340,7 +4341,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; * conf->upstream.hide_headers_hash = { NULL, 0 }; - * conf->upstream.ssl_name = NULL; * * conf->headers.lengths = NULL; * conf->headers.values = NULL; @@ -4352,8 +4352,6 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) * conf->ssl_ciphers = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.local = NGX_CONF_UNSET_PTR; @@ -4373,10 +4371,13 @@ ngx_http_grpc_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; + 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->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -4468,10 +4469,8 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -4482,11 +4481,12 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -4842,15 +4842,15 @@ ngx_http_grpc_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (glcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (glcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - glcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + glcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (glcf->ssl_passwords == NULL) { + if (glcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -4896,29 +4896,43 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = glcf->upstream.ssl; - if (glcf->ssl_certificate.len) { - - if (glcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"grpc_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &glcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->ssl_certificate, - &glcf->ssl_certificate_key, glcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (glcf->upstream.ssl_certificate) { + + if (glcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"grpc_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &glcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (glcf->upstream.ssl_certificate->lengths + || glcf->upstream.ssl_certificate_key->lengths) + { + glcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, glcf->upstream.ssl_passwords); + if (glcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, glcf->upstream.ssl, + &glcf->upstream.ssl_certificate->value, + &glcf->upstream.ssl_certificate_key->value, + glcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (glcf->upstream.ssl_verify) { if (glcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c index 0e93fbd..9c3f627 100644 --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -11,31 +11,33 @@ #define NGX_HTTP_MP4_TRAK_ATOM 0 #define NGX_HTTP_MP4_TKHD_ATOM 1 -#define NGX_HTTP_MP4_MDIA_ATOM 2 -#define NGX_HTTP_MP4_MDHD_ATOM 3 -#define NGX_HTTP_MP4_HDLR_ATOM 4 -#define NGX_HTTP_MP4_MINF_ATOM 5 -#define NGX_HTTP_MP4_VMHD_ATOM 6 -#define NGX_HTTP_MP4_SMHD_ATOM 7 -#define NGX_HTTP_MP4_DINF_ATOM 8 -#define NGX_HTTP_MP4_STBL_ATOM 9 -#define NGX_HTTP_MP4_STSD_ATOM 10 -#define NGX_HTTP_MP4_STTS_ATOM 11 -#define NGX_HTTP_MP4_STTS_DATA 12 -#define NGX_HTTP_MP4_STSS_ATOM 13 -#define NGX_HTTP_MP4_STSS_DATA 14 -#define NGX_HTTP_MP4_CTTS_ATOM 15 -#define NGX_HTTP_MP4_CTTS_DATA 16 -#define NGX_HTTP_MP4_STSC_ATOM 17 -#define NGX_HTTP_MP4_STSC_START 18 -#define NGX_HTTP_MP4_STSC_DATA 19 -#define NGX_HTTP_MP4_STSC_END 20 -#define NGX_HTTP_MP4_STSZ_ATOM 21 -#define NGX_HTTP_MP4_STSZ_DATA 22 -#define NGX_HTTP_MP4_STCO_ATOM 23 -#define NGX_HTTP_MP4_STCO_DATA 24 -#define NGX_HTTP_MP4_CO64_ATOM 25 -#define NGX_HTTP_MP4_CO64_DATA 26 +#define NGX_HTTP_MP4_EDTS_ATOM 2 +#define NGX_HTTP_MP4_ELST_ATOM 3 +#define NGX_HTTP_MP4_MDIA_ATOM 4 +#define NGX_HTTP_MP4_MDHD_ATOM 5 +#define NGX_HTTP_MP4_HDLR_ATOM 6 +#define NGX_HTTP_MP4_MINF_ATOM 7 +#define NGX_HTTP_MP4_VMHD_ATOM 8 +#define NGX_HTTP_MP4_SMHD_ATOM 9 +#define NGX_HTTP_MP4_DINF_ATOM 10 +#define NGX_HTTP_MP4_STBL_ATOM 11 +#define NGX_HTTP_MP4_STSD_ATOM 12 +#define NGX_HTTP_MP4_STTS_ATOM 13 +#define NGX_HTTP_MP4_STTS_DATA 14 +#define NGX_HTTP_MP4_STSS_ATOM 15 +#define NGX_HTTP_MP4_STSS_DATA 16 +#define NGX_HTTP_MP4_CTTS_ATOM 17 +#define NGX_HTTP_MP4_CTTS_DATA 18 +#define NGX_HTTP_MP4_STSC_ATOM 19 +#define NGX_HTTP_MP4_STSC_START 20 +#define NGX_HTTP_MP4_STSC_DATA 21 +#define NGX_HTTP_MP4_STSC_END 22 +#define NGX_HTTP_MP4_STSZ_ATOM 23 +#define NGX_HTTP_MP4_STSZ_DATA 24 +#define NGX_HTTP_MP4_STCO_ATOM 25 +#define NGX_HTTP_MP4_STCO_DATA 26 +#define NGX_HTTP_MP4_CO64_ATOM 27 +#define NGX_HTTP_MP4_CO64_DATA 28 #define NGX_HTTP_MP4_LAST_ATOM NGX_HTTP_MP4_CO64_DATA @@ -43,6 +45,7 @@ typedef struct { size_t buffer_size; size_t max_buffer_size; + ngx_flag_t start_key_frame; } ngx_http_mp4_conf_t; @@ -53,6 +56,25 @@ typedef struct { } ngx_mp4_stsc_entry_t; +typedef struct { + u_char size[4]; + u_char name[4]; +} ngx_mp4_edts_atom_t; + + +typedef struct { + u_char size[4]; + u_char name[4]; + u_char version[1]; + u_char flags[3]; + u_char entries[4]; + u_char duration[8]; + u_char media_time[8]; + u_char media_rate[2]; + u_char reserved[2]; +} ngx_mp4_elst_atom_t; + + typedef struct { uint32_t timescale; uint32_t time_to_sample_entries; @@ -70,6 +92,9 @@ typedef struct { ngx_uint_t end_chunk_samples; uint64_t start_chunk_samples_size; uint64_t end_chunk_samples_size; + uint64_t duration; + uint64_t prefix; + uint64_t movie_duration; off_t start_offset; off_t end_offset; @@ -85,6 +110,8 @@ typedef struct { ngx_buf_t trak_atom_buf; ngx_buf_t tkhd_atom_buf; + ngx_buf_t edts_atom_buf; + ngx_buf_t elst_atom_buf; ngx_buf_t mdia_atom_buf; ngx_buf_t mdhd_atom_buf; ngx_buf_t hdlr_atom_buf; @@ -111,6 +138,8 @@ typedef struct { ngx_buf_t co64_atom_buf; ngx_buf_t co64_data_buf; + ngx_mp4_edts_atom_t edts_atom; + ngx_mp4_elst_atom_t elst_atom; ngx_mp4_stsc_entry_t stsc_start_chunk_entry; ngx_mp4_stsc_entry_t stsc_end_chunk_entry; } ngx_http_mp4_trak_t; @@ -186,6 +215,14 @@ typedef struct { ((u_char *) (p))[6] = n3; \ ((u_char *) (p))[7] = n4 +#define ngx_mp4_get_16value(p) \ + ( ((uint16_t) ((u_char *) (p))[0] << 8) \ + + ( ((u_char *) (p))[1]) ) + +#define ngx_mp4_set_16value(p, n) \ + ((u_char *) (p))[0] = (u_char) ((n) >> 8); \ + ((u_char *) (p))[1] = (u_char) (n) + #define ngx_mp4_get_32value(p) \ ( ((uint32_t) ((u_char *) (p))[0] << 24) \ + ( ((u_char *) (p))[1] << 16) \ @@ -253,6 +290,8 @@ static void ngx_http_mp4_update_mdia_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_minf_atom(ngx_http_mp4_file_t *mp4, @@ -267,6 +306,8 @@ static ngx_int_t ngx_http_mp4_read_smhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); +static void ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak); static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_read_stsd_atom(ngx_http_mp4_file_t *mp4, @@ -277,6 +318,8 @@ static ngx_int_t ngx_http_mp4_update_stts_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak); static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start); +static uint32_t ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak, uint32_t start_sample); static ngx_int_t ngx_http_mp4_read_stss_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size); static ngx_int_t ngx_http_mp4_update_stss_atom(ngx_http_mp4_file_t *mp4, @@ -340,6 +383,13 @@ static ngx_command_t ngx_http_mp4_commands[] = { offsetof(ngx_http_mp4_conf_t, max_buffer_size), NULL }, + { ngx_string("mp4_start_key_frame"), + 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_mp4_conf_t, start_key_frame), + NULL }, + ngx_null_command }; @@ -822,10 +872,11 @@ ngx_http_mp4_process(ngx_http_mp4_file_t *mp4) ngx_http_mp4_update_stbl_atom(mp4, &trak[i]); ngx_http_mp4_update_minf_atom(mp4, &trak[i]); - trak[i].size += trak[i].mdhd_size; + ngx_http_mp4_update_mdhd_atom(mp4, &trak[i]); trak[i].size += trak[i].hdlr_size; ngx_http_mp4_update_mdia_atom(mp4, &trak[i]); trak[i].size += trak[i].tkhd_size; + ngx_http_mp4_update_edts_atom(mp4, &trak[i]); ngx_http_mp4_update_trak_atom(mp4, &trak[i]); mp4->moov_size += trak[i].size; @@ -1587,6 +1638,7 @@ ngx_http_mp4_read_tkhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->tkhd_size = atom_size; + trak->movie_duration = duration; ngx_mp4_set_32value(tkhd_atom->size, atom_size); @@ -1749,16 +1801,10 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) trak = ngx_mp4_last_trak(mp4); trak->mdhd_size = atom_size; trak->timescale = timescale; + trak->duration = duration; ngx_mp4_set_32value(mdhd_atom->size, atom_size); - if (mdhd_atom->version[0] == 0) { - ngx_mp4_set_32value(mdhd_atom->duration, duration); - - } else { - ngx_mp4_set_64value(mdhd64_atom->duration, duration); - } - atom = &trak->mdhd_atom_buf; atom->temporary = 1; atom->pos = atom_header; @@ -1772,6 +1818,33 @@ ngx_http_mp4_read_mdhd_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_mdhd_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_mdhd_atom_t *mdhd_atom; + ngx_mp4_mdhd64_atom_t *mdhd64_atom; + + atom = trak->out[NGX_HTTP_MP4_MDHD_ATOM].buf; + if (atom == NULL) { + return; + } + + mdhd_atom = (ngx_mp4_mdhd_atom_t *) atom->pos; + mdhd64_atom = (ngx_mp4_mdhd64_atom_t *) atom->pos; + + if (mdhd_atom->version[0] == 0) { + ngx_mp4_set_32value(mdhd_atom->duration, trak->duration); + + } else { + ngx_mp4_set_64value(mdhd64_atom->duration, trak->duration); + } + + trak->size += trak->mdhd_size; +} + + static ngx_int_t ngx_http_mp4_read_hdlr_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) { @@ -1961,6 +2034,59 @@ ngx_http_mp4_read_stbl_atom(ngx_http_mp4_file_t *mp4, uint64_t atom_data_size) } +static void +ngx_http_mp4_update_edts_atom(ngx_http_mp4_file_t *mp4, + ngx_http_mp4_trak_t *trak) +{ + ngx_buf_t *atom; + ngx_mp4_elst_atom_t *elst_atom; + ngx_mp4_edts_atom_t *edts_atom; + + if (trak->prefix == 0) { + return; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 edts atom update prefix:%uL", trak->prefix); + + edts_atom = &trak->edts_atom; + ngx_mp4_set_32value(edts_atom->size, sizeof(ngx_mp4_edts_atom_t) + + sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(edts_atom, 'e', 'd', 't', 's'); + + atom = &trak->edts_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) edts_atom; + atom->last = (u_char *) edts_atom + sizeof(ngx_mp4_edts_atom_t); + + trak->out[NGX_HTTP_MP4_EDTS_ATOM].buf = atom; + + elst_atom = &trak->elst_atom; + ngx_mp4_set_32value(elst_atom->size, sizeof(ngx_mp4_elst_atom_t)); + ngx_mp4_set_atom_name(elst_atom, 'e', 'l', 's', 't'); + + elst_atom->version[0] = 1; + elst_atom->flags[0] = 0; + elst_atom->flags[1] = 0; + elst_atom->flags[2] = 0; + + ngx_mp4_set_32value(elst_atom->entries, 1); + ngx_mp4_set_64value(elst_atom->duration, trak->movie_duration); + ngx_mp4_set_64value(elst_atom->media_time, trak->prefix); + ngx_mp4_set_16value(elst_atom->media_rate, 1); + ngx_mp4_set_16value(elst_atom->reserved, 0); + + atom = &trak->elst_atom_buf; + atom->temporary = 1; + atom->pos = (u_char *) elst_atom; + atom->last = (u_char *) elst_atom + sizeof(ngx_mp4_elst_atom_t); + + trak->out[NGX_HTTP_MP4_ELST_ATOM].buf = atom; + + trak->size += sizeof(ngx_mp4_edts_atom_t) + sizeof(ngx_mp4_elst_atom_t); +} + + static void ngx_http_mp4_update_stbl_atom(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak) @@ -2159,7 +2285,7 @@ static ngx_int_t ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, ngx_uint_t start) { - uint32_t count, duration, rest; + uint32_t count, duration, rest, key_prefix; uint64_t start_time; ngx_buf_t *data; ngx_uint_t start_sample, entries, start_sec; @@ -2183,7 +2309,7 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, data = trak->out[NGX_HTTP_MP4_STTS_DATA].buf; - start_time = (uint64_t) start_sec * trak->timescale / 1000; + start_time = (uint64_t) start_sec * trak->timescale / 1000 + trak->prefix; entries = trak->time_to_sample_entries; start_sample = 0; @@ -2229,6 +2355,26 @@ ngx_http_mp4_crop_stts_data(ngx_http_mp4_file_t *mp4, found: if (start) { + key_prefix = ngx_http_mp4_seek_key_frame(mp4, trak, start_sample); + + start_sample -= key_prefix; + + while (rest < key_prefix) { + trak->prefix += rest * duration; + key_prefix -= rest; + + entry--; + entries++; + + count = ngx_mp4_get_32value(entry->count); + duration = ngx_mp4_get_32value(entry->duration); + rest = count; + } + + trak->prefix += key_prefix * duration; + trak->duration += trak->prefix; + rest -= key_prefix; + ngx_mp4_set_32value(entry->count, count - rest); data->pos = (u_char *) entry; trak->time_to_sample_entries = entries; @@ -2253,6 +2399,49 @@ found: } +static uint32_t +ngx_http_mp4_seek_key_frame(ngx_http_mp4_file_t *mp4, ngx_http_mp4_trak_t *trak, + uint32_t start_sample) +{ + uint32_t key_prefix, sample, *entry, *end; + ngx_buf_t *data; + ngx_http_mp4_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(mp4->request, ngx_http_mp4_module); + if (!conf->start_key_frame) { + return 0; + } + + data = trak->out[NGX_HTTP_MP4_STSS_DATA].buf; + if (data == NULL) { + return 0; + } + + entry = (uint32_t *) data->pos; + end = (uint32_t *) data->last; + + /* sync samples starts from 1 */ + start_sample++; + + key_prefix = 0; + + while (entry < end) { + sample = ngx_mp4_get_32value(entry); + if (sample > start_sample) { + break; + } + + key_prefix = start_sample - sample; + entry++; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, + "mp4 key frame prefix:%uD", key_prefix); + + return key_prefix; +} + + typedef struct { u_char size[4]; u_char name[4]; @@ -3590,6 +3779,7 @@ ngx_http_mp4_create_conf(ngx_conf_t *cf) conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->max_buffer_size = NGX_CONF_UNSET_SIZE; + conf->start_key_frame = NGX_CONF_UNSET; return conf; } @@ -3604,6 +3794,7 @@ ngx_http_mp4_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 512 * 1024); ngx_conf_merge_size_value(conf->max_buffer_size, prev->max_buffer_size, 10 * 1024 * 1024); + ngx_conf_merge_value(conf->start_key_frame, prev->start_key_frame, 0); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index a63c3ed..7c4061c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -124,9 +124,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_proxy_loc_conf_t; @@ -753,16 +750,16 @@ static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate), + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("proxy_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("proxy_ssl_password_file"), @@ -1189,7 +1186,7 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } else { @@ -1302,7 +1299,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->space_in_uri || r->internal) { + if (r->quoted_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } @@ -2022,10 +2019,12 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } @@ -2338,6 +2337,7 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes) ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "upstream sent more data than specified in " "\"Content-Length\" header"); + u->keepalive = 0; return NGX_OK; } @@ -3327,9 +3327,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.store_lengths = NULL; * conf->upstream.store_values = NULL; - * conf->upstream.ssl_name = NULL; * - * conf->method = NULL; * conf->location = NULL; * conf->url = { 0, NULL }; * conf->headers.lengths = NULL; @@ -3347,8 +3345,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) * conf->ssl_ciphers = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; */ conf->upstream.store = NGX_CONF_UNSET; @@ -3400,20 +3396,26 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; + 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->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif /* "proxy_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; + conf->upstream.change_buffering = 1; + conf->headers_source = NGX_CONF_UNSET_PTR; + conf->method = NGX_CONF_UNSET_PTR; + conf->redirect = NGX_CONF_UNSET; - conf->upstream.change_buffering = 1; conf->cookie_domains = NGX_CONF_UNSET_PTR; conf->cookie_paths = NGX_CONF_UNSET_PTR; @@ -3708,10 +3710,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif - if (conf->method == NULL) { - conf->method = prev->method; - } - ngx_conf_merge_value(conf->upstream.pass_request_headers, prev->upstream.pass_request_headers, 1); ngx_conf_merge_value(conf->upstream.pass_request_body, @@ -3732,10 +3730,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -3746,11 +3742,12 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -3761,6 +3758,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) #endif + ngx_conf_merge_ptr_value(conf->method, prev->method, NULL); + ngx_conf_merge_value(conf->redirect, prev->redirect, 1); if (conf->redirect) { @@ -4859,15 +4858,15 @@ ngx_http_proxy_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (plcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (plcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - plcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + plcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (plcf->ssl_passwords == NULL) { + if (plcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -4946,29 +4945,43 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = plcf->upstream.ssl; - if (plcf->ssl_certificate.len) { - - if (plcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &plcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->ssl_certificate, - &plcf->ssl_certificate_key, plcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (plcf->upstream.ssl_certificate) { + + if (plcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &plcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (plcf->upstream.ssl_certificate->lengths + || plcf->upstream.ssl_certificate_key->lengths) + { + plcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, plcf->upstream.ssl_passwords); + if (plcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, plcf->upstream.ssl, + &plcf->upstream.ssl_certificate->value, + &plcf->upstream.ssl_certificate_key->value, + plcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (plcf->upstream.ssl_verify) { if (plcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c index 600999c..e5d31ae 100644 --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1140,10 +1140,12 @@ ngx_http_scgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c index 536e09a..4d4ce6a 100644 --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -302,11 +302,12 @@ ngx_http_secure_link_create_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * - * conf->variable = NULL; - * conf->md5 = NULL; * conf->secret = { 0, NULL }; */ + conf->variable = NGX_CONF_UNSET_PTR; + conf->md5 = NGX_CONF_UNSET_PTR; + return conf; } @@ -318,6 +319,9 @@ ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_http_secure_link_conf_t *conf = child; if (conf->secret.data) { + ngx_conf_init_ptr_value(conf->variable, NULL); + ngx_conf_init_ptr_value(conf->md5, NULL); + if (conf->variable || conf->md5) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"secure_link_secret\" cannot be mixed with " @@ -328,13 +332,8 @@ ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_OK; } - if (conf->variable == NULL) { - conf->variable = prev->variable; - } - - if (conf->md5 == NULL) { - conf->md5 = prev->md5; - } + ngx_conf_merge_ptr_value(conf->variable, prev->variable, NULL); + ngx_conf_merge_ptr_value(conf->md5, prev->md5, NULL); if (conf->variable == NULL && conf->md5 == NULL) { conf->secret = prev->secret; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index a47d696..d74d460 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,7 +17,7 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" -#define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" +#define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9" #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation @@ -26,11 +26,6 @@ static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char *in, unsigned int inlen, void *arg); #endif -#ifdef TLSEXT_TYPE_next_proto_neg -static int ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg); -#endif - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_ssl_variable(ngx_http_request_t *r, @@ -347,6 +342,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -363,6 +361,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -444,22 +445,20 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, hc = c->data; if (hc->addr_conf->http2) { - srv = - (unsigned char *) NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_V2_ALPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - + 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_NPN_ADVERTISE; - srvlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; + 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, in, inlen) != OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_NOACK; + return SSL_TLSEXT_ERR_ALERT_FATAL; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -471,44 +470,6 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out, #endif -#ifdef TLSEXT_TYPE_next_proto_neg - -static int -ngx_http_ssl_npn_advertised(ngx_ssl_conn_t *ssl_conn, - const unsigned char **out, unsigned int *outlen, void *arg) -{ -#if (NGX_HTTP_V2 || NGX_DEBUG) - ngx_connection_t *c; - - c = ngx_ssl_get_connection(ssl_conn); - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL NPN advertised"); -#endif - -#if (NGX_HTTP_V2) - { - ngx_http_connection_t *hc; - - hc = c->data; - - if (hc->addr_conf->http2) { - *out = - (unsigned char *) NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; - } - } -#endif - - *out = (unsigned char *) NGX_HTTP_NPN_ADVERTISE; - *outlen = sizeof(NGX_HTTP_NPN_ADVERTISE) - 1; - - return SSL_TLSEXT_ERR_OK; -} - -#endif - - static ngx_int_t ngx_http_ssl_static_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -792,10 +753,12 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_http_ssl_alpn_select, NULL); #endif -#ifdef TLSEXT_TYPE_next_proto_neg - SSL_CTX_set_next_protos_advertised_cb(conf->ssl.ctx, - ngx_http_ssl_npn_advertised, NULL); -#endif + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; @@ -829,13 +792,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - conf->ssl.buffer_size = conf->buffer_size; if (conf->verify) { diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c index 282d6ee..cf29d5a 100644 --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -50,6 +50,7 @@ ngx_http_static_handler(ngx_http_request_t *r) { u_char *last, *location; size_t root, len; + uintptr_t escape; ngx_str_t path; ngx_int_t rc; ngx_uint_t level; @@ -155,14 +156,18 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - len = r->uri.len + 1; + escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, + NGX_ESCAPE_URI); - if (!clcf->alias && r->args.len == 0) { + if (!clcf->alias && r->args.len == 0 && escape == 0) { + len = r->uri.len + 1; location = path.data + root; *last = '/'; } else { + len = r->uri.len + escape + 1; + if (r->args.len) { len += r->args.len + 1; } @@ -173,7 +178,13 @@ ngx_http_static_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - last = ngx_copy(location, r->uri.data, r->uri.len); + if (escape) { + last = (u_char *) ngx_escape_uri(location, r->uri.data, + r->uri.len, NGX_ESCAPE_URI); + + } else { + last = ngx_copy(location, r->uri.data, r->uri.len); + } *last = '/'; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index 1334f44..d46741a 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -54,9 +54,6 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; - ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; #endif } ngx_http_uwsgi_loc_conf_t; @@ -548,16 +545,16 @@ static ngx_command_t ngx_http_uwsgi_commands[] = { { ngx_string("uwsgi_ssl_certificate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate), + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate), NULL }, { ngx_string("uwsgi_ssl_certificate_key"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_zero_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_uwsgi_loc_conf_t, ssl_certificate_key), + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_certificate_key), NULL }, { ngx_string("uwsgi_ssl_password_file"), @@ -1364,10 +1361,12 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r) return NGX_AGAIN; } - /* there was error while a header line parsing */ + /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid header"); + "upstream sent invalid header: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); return NGX_HTTP_UPSTREAM_INVALID_HEADER; } @@ -1509,10 +1508,13 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf) #if (NGX_HTTP_SSL) conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; + conf->upstream.ssl_name = NGX_CONF_UNSET_PTR; conf->upstream.ssl_server_name = NGX_CONF_UNSET; conf->upstream.ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; - conf->ssl_passwords = NGX_CONF_UNSET_PTR; + 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->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -1824,10 +1826,8 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->upstream.ssl_name == NULL) { - conf->upstream.ssl_name = prev->upstream.ssl_name; - } - + ngx_conf_merge_ptr_value(conf->upstream.ssl_name, + prev->upstream.ssl_name, NULL); ngx_conf_merge_value(conf->upstream.ssl_server_name, prev->upstream.ssl_server_name, 0); ngx_conf_merge_value(conf->upstream.ssl_verify, @@ -1838,11 +1838,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) prev->ssl_trusted_certificate, ""); ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); - ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate, + prev->upstream.ssl_certificate, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_certificate_key, + prev->upstream.ssl_certificate_key, NULL); + ngx_conf_merge_ptr_value(conf->upstream.ssl_passwords, + prev->upstream.ssl_passwords, NULL); ngx_conf_merge_ptr_value(conf->ssl_conf_commands, prev->ssl_conf_commands, NULL); @@ -2377,15 +2378,15 @@ ngx_http_uwsgi_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_str_t *value; - if (uwcf->ssl_passwords != NGX_CONF_UNSET_PTR) { + if (uwcf->upstream.ssl_passwords != NGX_CONF_UNSET_PTR) { return "is duplicate"; } value = cf->args->elts; - uwcf->ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); + uwcf->upstream.ssl_passwords = ngx_ssl_read_password_file(cf, &value[1]); - if (uwcf->ssl_passwords == NULL) { + if (uwcf->upstream.ssl_passwords == NULL) { return NGX_CONF_ERROR; } @@ -2431,29 +2432,43 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = uwcf->upstream.ssl; - if (uwcf->ssl_certificate.len) { - - if (uwcf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"uwsgi_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &uwcf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->ssl_certificate, - &uwcf->ssl_certificate_key, uwcf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (uwcf->upstream.ssl_certificate) { + + if (uwcf->upstream.ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"uwsgi_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &uwcf->upstream.ssl_certificate->value); + return NGX_ERROR; + } + + if (uwcf->upstream.ssl_certificate->lengths + || uwcf->upstream.ssl_certificate_key->lengths) + { + uwcf->upstream.ssl_passwords = + ngx_ssl_preserve_passwords(cf, uwcf->upstream.ssl_passwords); + if (uwcf->upstream.ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, + &uwcf->upstream.ssl_certificate->value, + &uwcf->upstream.ssl_certificate_key->value, + uwcf->upstream.ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (uwcf->upstream.ssl_verify) { if (uwcf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index e1d3d00..73c08d5 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -37,6 +37,8 @@ static ngx_int_t ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf); static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf, ngx_http_core_loc_conf_t *pclcf); +static ngx_int_t ngx_http_escape_location_name(ngx_conf_t *cf, + ngx_http_core_loc_conf_t *clcf); static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two); static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf, @@ -882,6 +884,41 @@ ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations, ngx_queue_insert_tail(*locations, &lq->queue); + if (ngx_http_escape_location_name(cf, clcf) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_escape_location_name(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf) +{ + u_char *p; + size_t len; + uintptr_t escape; + + escape = 2 * ngx_escape_uri(NULL, clcf->name.data, clcf->name.len, + NGX_ESCAPE_URI); + + if (escape) { + len = clcf->name.len + escape; + + p = ngx_pnalloc(cf->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + clcf->escaped_name.len = len; + clcf->escaped_name.data = p; + + ngx_escape_uri(p, clcf->name.data, clcf->name.len, NGX_ESCAPE_URI); + + } else { + clcf->escaped_name = clcf->name; + } + return NGX_OK; } @@ -1301,13 +1338,12 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, } #if (NGX_HTTP_V2 && NGX_HTTP_SSL \ - && !defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - && !defined TLSEXT_TYPE_next_proto_neg) + && !defined TLSEXT_TYPE_application_layer_protocol_negotiation) if (lsopt->http2 && lsopt->ssl) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "nginx was built with OpenSSL that lacks ALPN " - "and NPN support, HTTP/2 is not enabled for %V", + "support, HTTP/2 is not enabled for %V", &lsopt->addr_text); } diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 8b43857..be8b7cd 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -167,6 +167,14 @@ ngx_uint_t ngx_http_degraded(ngx_http_request_t *); #endif +#if (NGX_HTTP_V2) +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, + ngx_uint_t lower); +#endif + + extern ngx_module_t ngx_http_module; extern ngx_str_t ngx_http_html_default_types[]; diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c index c8ad5da..bd3028b 100644 --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -19,10 +19,6 @@ typedef struct { static void ngx_http_copy_aio_handler(ngx_output_chain_ctx_t *ctx, ngx_file_t *file); static void ngx_http_copy_aio_event_handler(ngx_event_t *ev); -#if (NGX_HAVE_AIO_SENDFILE) -static ssize_t ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file); -static void ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev); -#endif #endif #if (NGX_THREADS) static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, @@ -128,9 +124,6 @@ ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) #if (NGX_HAVE_FILE_AIO) if (ngx_file_aio && clcf->aio == NGX_HTTP_AIO_ON) { ctx->aio_handler = ngx_http_copy_aio_handler; -#if (NGX_HAVE_AIO_SENDFILE) - ctx->aio_preload = ngx_http_copy_aio_sendfile_preload; -#endif } #endif @@ -207,53 +200,6 @@ ngx_http_copy_aio_event_handler(ngx_event_t *ev) ngx_http_run_posted_requests(c); } - -#if (NGX_HAVE_AIO_SENDFILE) - -static ssize_t -ngx_http_copy_aio_sendfile_preload(ngx_buf_t *file) -{ - ssize_t n; - static u_char buf[1]; - ngx_event_aio_t *aio; - ngx_http_request_t *r; - ngx_output_chain_ctx_t *ctx; - - n = ngx_file_aio_read(file->file, buf, 1, file->file_pos, NULL); - - if (n == NGX_AGAIN) { - aio = file->file->aio; - aio->handler = ngx_http_copy_aio_sendfile_event_handler; - - r = aio->data; - r->main->blocked++; - r->aio = 1; - - ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); - ctx->aio = 1; - } - - return n; -} - - -static void -ngx_http_copy_aio_sendfile_event_handler(ngx_event_t *ev) -{ - ngx_event_aio_t *aio; - ngx_http_request_t *r; - - aio = ev->data; - r = aio->data; - - r->main->blocked--; - r->aio = 0; - ev->complete = 0; - - r->connection->write->handler(r->connection->write); -} - -#endif #endif @@ -263,6 +209,7 @@ static ngx_int_t ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_output_chain_ctx_t *ctx; @@ -270,6 +217,27 @@ ngx_http_copy_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; @@ -323,6 +291,20 @@ ngx_http_copy_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 6664fa6..c7463dc 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1010,10 +1010,10 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, ngx_str_set(&r->headers_out.location->key, "Location"); if (r->args.len == 0) { - r->headers_out.location->value = clcf->name; + r->headers_out.location->value = clcf->escaped_name; } else { - len = clcf->name.len + 1 + r->args.len; + len = clcf->escaped_name.len + 1 + r->args.len; p = ngx_pnalloc(r->pool, len); if (p == NULL) { @@ -1025,7 +1025,7 @@ ngx_http_core_find_config_phase(ngx_http_request_t *r, r->headers_out.location->value.len = len; r->headers_out.location->value.data = p; - p = ngx_cpymem(p, clcf->name.data, clcf->name.len); + p = ngx_cpymem(p, clcf->escaped_name.data, clcf->escaped_name.len); *p++ = '?'; ngx_memcpy(p, r->args.data, r->args.len); } @@ -3467,6 +3467,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) /* * set by ngx_pcalloc(): * + * clcf->escaped_name = { 0, NULL }; * clcf->root = { 0, NULL }; * clcf->limit_except = 0; * clcf->post_action = { 0, NULL }; @@ -3479,8 +3480,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * clcf->exact_match = 0; * clcf->auto_redirect = 0; * clcf->alias = 0; - * clcf->limit_rate = NULL; - * clcf->limit_rate_after = NULL; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; */ @@ -3512,6 +3511,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; + clcf->limit_rate = NGX_CONF_UNSET_PTR; + clcf->limit_rate_after = NGX_CONF_UNSET_PTR; clcf->keepalive_time = NGX_CONF_UNSET_MSEC; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; @@ -3719,7 +3720,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->internal, prev->internal, 0); ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_size_value(conf->sendfile_max_chunk, - prev->sendfile_max_chunk, 0); + prev->sendfile_max_chunk, 2 * 1024 * 1024); ngx_conf_merge_size_value(conf->subrequest_output_buffer_size, prev->subrequest_output_buffer_size, (size_t) ngx_pagesize); @@ -3743,13 +3744,9 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); - if (conf->limit_rate == NULL) { - conf->limit_rate = prev->limit_rate; - } - - if (conf->limit_rate_after == NULL) { - conf->limit_rate_after = prev->limit_rate_after; - } + ngx_conf_merge_ptr_value(conf->limit_rate, prev->limit_rate, NULL); + ngx_conf_merge_ptr_value(conf->limit_rate_after, + prev->limit_rate_after, NULL); ngx_conf_merge_msec_value(conf->keepalive_time, prev->keepalive_time, 3600000); @@ -4571,19 +4568,6 @@ ngx_http_core_set_aio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) #endif } -#if (NGX_HAVE_AIO_SENDFILE) - - if (ngx_strcmp(value[1].data, "sendfile") == 0) { - clcf->aio = NGX_HTTP_AIO_ON; - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the \"sendfile\" parameter of " - "the \"aio\" directive is deprecated"); - return NGX_CONF_OK; - } - -#endif - if (ngx_strncmp(value[1].data, "threads", 7) == 0 && (value[1].len == 7 || value[1].data[7] == '=')) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 2341fd4..004a98e 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -299,6 +299,7 @@ typedef struct { struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ + ngx_str_t escaped_name; #if (NGX_PCRE) ngx_http_regex_t *regex; @@ -501,8 +502,8 @@ ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, - ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr, - ngx_http_post_subrequest_t *psr, ngx_uint_t flags); + ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, + ngx_http_post_subrequest_t *ps, ngx_uint_t flags); ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index 9b89405..76f6e96 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -197,6 +197,10 @@ ngx_http_header_filter(ngx_http_request_t *r) } } + if (r->keepalive && (ngx_terminate || ngx_exiting)) { + r->keepalive = 0; + } + len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 /* the end of the header */ + sizeof(CRLF) - 1; diff --git a/src/http/v2/ngx_http_v2_huff_decode.c b/src/http/ngx_http_huff_decode.c similarity index 99% rename from src/http/v2/ngx_http_v2_huff_decode.c rename to src/http/ngx_http_huff_decode.c index 49ca576..14b7b78 100644 --- a/src/http/v2/ngx_http_v2_huff_decode.c +++ b/src/http/ngx_http_huff_decode.c @@ -15,14 +15,14 @@ typedef struct { u_char emit; u_char sym; u_char ending; -} ngx_http_v2_huff_decode_code_t; +} ngx_http_huff_decode_code_t; -static ngx_inline ngx_int_t ngx_http_v2_huff_decode_bits(u_char *state, +static ngx_inline ngx_int_t ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst); -static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = +static ngx_http_huff_decode_code_t ngx_http_huff_decode_codes[256][16] = { /* 0 */ { @@ -2640,7 +2640,7 @@ static ngx_http_v2_huff_decode_code_t ngx_http_v2_huff_decode_codes[256][16] = ngx_int_t -ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, +ngx_http_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, ngx_uint_t last, ngx_log_t *log) { u_char *end, ch, ending; @@ -2653,7 +2653,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, while (src != end) { ch = *src++; - if (ngx_http_v2_huff_decode_bits(state, &ending, ch >> 4, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch >> 4, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2663,7 +2663,7 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, return NGX_ERROR; } - if (ngx_http_v2_huff_decode_bits(state, &ending, ch & 0xf, dst) + if (ngx_http_huff_decode_bits(state, &ending, ch & 0xf, dst) != NGX_OK) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0, @@ -2692,12 +2692,12 @@ ngx_http_v2_huff_decode(u_char *state, u_char *src, size_t len, u_char **dst, static ngx_inline ngx_int_t -ngx_http_v2_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, +ngx_http_huff_decode_bits(u_char *state, u_char *ending, ngx_uint_t bits, u_char **dst) { - ngx_http_v2_huff_decode_code_t code; + ngx_http_huff_decode_code_t code; - code = ngx_http_v2_huff_decode_codes[*state][bits]; + code = ngx_http_huff_decode_codes[*state][bits]; if (code.next == *state) { return NGX_ERROR; diff --git a/src/http/v2/ngx_http_v2_huff_encode.c b/src/http/ngx_http_huff_encode.c similarity index 93% rename from src/http/v2/ngx_http_v2_huff_encode.c rename to src/http/ngx_http_huff_encode.c index 3f822cd..c03b153 100644 --- a/src/http/v2/ngx_http_v2_huff_encode.c +++ b/src/http/ngx_http_huff_encode.c @@ -14,10 +14,10 @@ typedef struct { uint32_t code; uint32_t len; -} ngx_http_v2_huff_encode_code_t; +} ngx_http_huff_encode_code_t; -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -87,7 +87,7 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table[256] = /* same as above, but embeds lowercase transformation */ -static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = +static ngx_http_huff_encode_code_t ngx_http_huff_encode_table_lc[256] = { {0x00001ff8, 13}, {0x007fffd8, 23}, {0x0fffffe2, 28}, {0x0fffffe3, 28}, {0x0fffffe4, 28}, {0x0fffffe5, 28}, {0x0fffffe6, 28}, {0x0fffffe7, 28}, @@ -161,10 +161,10 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #if (NGX_HAVE_LITTLE_ENDIAN) #if (NGX_HAVE_GCC_BSWAP64) -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = __builtin_bswap64(buf)) #else -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ ((dst)[0] = (u_char) ((buf) >> 56), \ (dst)[1] = (u_char) ((buf) >> 48), \ (dst)[2] = (u_char) ((buf) >> 40), \ @@ -176,28 +176,28 @@ static ngx_http_v2_huff_encode_code_t ngx_http_v2_huff_encode_table_lc[256] = #endif #else /* !NGX_HAVE_LITTLE_ENDIAN */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint64_t *) (dst) = (buf)) #endif #else /* NGX_PTR_SIZE == 4 */ -#define ngx_http_v2_huff_encode_buf(dst, buf) \ +#define ngx_http_huff_encode_buf(dst, buf) \ (*(uint32_t *) (dst) = htonl(buf)) #endif size_t -ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) +ngx_http_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) { - u_char *end; - size_t hlen; - ngx_uint_t buf, pending, code; - ngx_http_v2_huff_encode_code_t *table, *next; + u_char *end; + size_t hlen; + ngx_uint_t buf, pending, code; + ngx_http_huff_encode_code_t *table, *next; - table = lower ? ngx_http_v2_huff_encode_table_lc - : ngx_http_v2_huff_encode_table; + table = lower ? ngx_http_huff_encode_table_lc + : ngx_http_huff_encode_table; hlen = 0; buf = 0; pending = 0; @@ -224,7 +224,7 @@ ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst, ngx_uint_t lower) buf |= code >> pending; - ngx_http_v2_huff_encode_buf(&dst[hlen], buf); + ngx_http_huff_encode_buf(&dst[hlen], buf); hlen += sizeof(buf); diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 20ad89a..6460da2 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -11,7 +11,7 @@ static uint32_t usual[] = { - 0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ 0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */ @@ -24,7 +24,7 @@ static uint32_t usual[] = { #endif /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0x7fffffff, /* 0111 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 */ @@ -116,10 +116,8 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) sw_host_end, sw_host_ip_literal, sw_port, - sw_host_http_09, sw_after_slash_in_uri, sw_check_uri, - sw_check_uri_http_09, sw_uri, sw_http_09, sw_http_H, @@ -246,6 +244,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->method = NGX_HTTP_OPTIONS; } + if (ngx_str7_cmp(m, 'C', 'O', 'N', 'N', 'E', 'C', 'T', ' ')) + { + r->method = NGX_HTTP_CONNECT; + } + break; case 8: @@ -393,7 +396,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; @@ -467,35 +470,13 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) */ r->uri_start = r->schema_end + 1; r->uri_end = r->schema_end + 2; - state = sw_host_http_09; + state = sw_http_09; break; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - /* space+ after "http://host[:port] " */ - case sw_host_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; - default: - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* check "/.", "//", "%", and "\" (Win32) in URI */ case sw_after_slash_in_uri: @@ -507,7 +488,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) switch (ch) { case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -547,9 +528,10 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } state = sw_check_uri; break; } @@ -579,7 +561,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; case ' ': r->uri_end = p; - state = sw_check_uri_http_09; + state = sw_http_09; break; case CR: r->uri_end = p; @@ -611,36 +593,14 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '+': r->plus_in_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; - } - break; - - /* space+ after URI */ - case sw_check_uri_http_09: - switch (ch) { - case ' ': - break; - case CR: - r->http_minor = 9; - state = sw_almost_done; - break; - case LF: - r->http_minor = 9; - goto done; - case 'H': - r->http_protocol.data = p; - state = sw_http_H; - break; default: - r->space_in_uri = 1; - state = sw_check_uri; - p--; + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } break; } break; - /* URI */ case sw_uri: @@ -665,8 +625,11 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case '#': r->complex_uri = 1; break; - case '\0': - return NGX_HTTP_PARSE_INVALID_REQUEST; + default: + if (ch < 0x20 || ch == 0x7f) { + return NGX_HTTP_PARSE_INVALID_REQUEST; + } + break; } break; @@ -687,10 +650,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) state = sw_http_H; break; default: - r->space_in_uri = 1; - state = sw_uri; - p--; - break; + return NGX_HTTP_PARSE_INVALID_REQUEST; } break; @@ -933,7 +893,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f || ch == ':') { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1001,7 +962,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, break; } - if (ch == '\0') { + if (ch <= 0x20 || ch == 0x7f) { + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -1024,6 +986,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: r->header_start = p; @@ -1047,6 +1010,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, r->header_end = p; goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; } break; @@ -1062,6 +1026,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b, case LF: goto done; case '\0': + r->header_end = p; return NGX_HTTP_PARSE_INVALID_HEADER; default: state = sw_value; @@ -1165,10 +1130,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - r->space_in_uri = 1; - state = sw_check_uri; - break; case '.': r->complex_uri = 1; state = sw_uri; @@ -1199,6 +1160,9 @@ ngx_http_parse_uri(ngx_http_request_t *r) r->plus_in_uri = 1; break; default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } state = sw_check_uri; break; } @@ -1226,9 +1190,6 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '.': r->uri_ext = p + 1; break; - case ' ': - r->space_in_uri = 1; - break; #if (NGX_WIN32) case '\\': r->complex_uri = 1; @@ -1250,6 +1211,11 @@ ngx_http_parse_uri(ngx_http_request_t *r) case '+': r->plus_in_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; @@ -1261,12 +1227,14 @@ ngx_http_parse_uri(ngx_http_request_t *r) } switch (ch) { - case ' ': - r->space_in_uri = 1; - break; case '#': r->complex_uri = 1; break; + default: + if (ch <= 0x20 || ch == 0x7f) { + return NGX_ERROR; + } + break; } break; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 136c461..013b715 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -607,7 +607,7 @@ ngx_http_alloc_request(ngx_connection_t *c) } #if (NGX_HTTP_SSL) - if (c->ssl) { + if (c->ssl && !c->ssl->sendfile) { r->main_filter_need_in_memory = 1; } #endif @@ -806,8 +806,7 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; #if (NGX_HTTP_V2 \ - && (defined TLSEXT_TYPE_application_layer_protocol_negotiation \ - || defined TLSEXT_TYPE_next_proto_neg)) + && defined TLSEXT_TYPE_application_layer_protocol_negotiation) { unsigned int len; const unsigned char *data; @@ -817,19 +816,8 @@ ngx_http_ssl_handshake_handler(ngx_connection_t *c) if (hc->addr_conf->http2) { -#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation SSL_get0_alpn_selected(c->ssl->connection, &data, &len); -#ifdef TLSEXT_TYPE_next_proto_neg - if (len == 0) { - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); - } -#endif - -#else /* TLSEXT_TYPE_next_proto_neg */ - SSL_get0_next_proto_negotiated(c->ssl->connection, &data, &len); -#endif - if (len == 2 && data[0] == 'h' && data[1] == '2') { ngx_http_v2_init(c->read); return; @@ -1043,12 +1031,14 @@ ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) } ngx_http_free_request(r, 0); + c->log->action = "SSL handshaking"; c->destroyed = 0; return 1; failed: ngx_http_free_request(r, 0); + c->log->action = "SSL handshaking"; c->destroyed = 0; return 0; } @@ -1262,7 +1252,7 @@ ngx_http_process_request_uri(ngx_http_request_t *r) r->unparsed_uri.len = r->uri_end - r->uri_start; r->unparsed_uri.data = r->uri_start; - r->valid_unparsed_uri = (r->space_in_uri || r->empty_path_in_uri) ? 0 : 1; + r->valid_unparsed_uri = r->empty_path_in_uri ? 0 : 1; if (r->uri_ext) { if (r->args_start) { @@ -1520,7 +1510,9 @@ ngx_http_process_request_headers(ngx_event_t *rev) /* rc == NGX_HTTP_PARSE_INVALID_HEADER */ ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent invalid header line"); + "client sent invalid header line: \"%*s\\x%02xd...\"", + r->header_end - r->header_name_start, + r->header_name_start, *r->header_end); ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); break; @@ -1978,20 +1970,28 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } - if (r->method == NGX_HTTP_TRACE) { - ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, - "client sent TRACE method"); - ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); - return NGX_ERROR; - } - if (r->headers_in.transfer_encoding) { + if (r->http_version < NGX_HTTP_VERSION_11) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/1.0 request with " + "\"Transfer-Encoding\" header"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + if (r->headers_in.transfer_encoding->value.len == 7 && ngx_strncasecmp(r->headers_in.transfer_encoding->value.data, (u_char *) "chunked", 7) == 0) { - r->headers_in.content_length = NULL; - r->headers_in.content_length_n = -1; + if (r->headers_in.content_length) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent \"Content-Length\" and " + "\"Transfer-Encoding\" headers " + "at the same time"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + r->headers_in.chunked = 1; } else { @@ -2011,6 +2011,20 @@ ngx_http_process_request_header(ngx_http_request_t *r) } } + if (r->method == NGX_HTTP_CONNECT) { + ngx_log_error(NGX_LOG_INFO, r->connection->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, r->connection->log, 0, + "client sent TRACE method"); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + return NGX_ERROR; + } + return NGX_OK; } @@ -2158,15 +2172,16 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc) } break; - case '\0': - return NGX_DECLINED; - default: if (ngx_path_separator(ch)) { return NGX_DECLINED; } + if (ch <= 0x20 || ch == 0x7f) { + return NGX_DECLINED; + } + if (ch >= 'A' && ch <= 'Z') { alloc = 1; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 6dfb4a4..b1269d2 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -25,22 +25,23 @@ #define NGX_HTTP_VERSION_11 1001 #define NGX_HTTP_VERSION_20 2000 -#define NGX_HTTP_UNKNOWN 0x0001 -#define NGX_HTTP_GET 0x0002 -#define NGX_HTTP_HEAD 0x0004 -#define NGX_HTTP_POST 0x0008 -#define NGX_HTTP_PUT 0x0010 -#define NGX_HTTP_DELETE 0x0020 -#define NGX_HTTP_MKCOL 0x0040 -#define NGX_HTTP_COPY 0x0080 -#define NGX_HTTP_MOVE 0x0100 -#define NGX_HTTP_OPTIONS 0x0200 -#define NGX_HTTP_PROPFIND 0x0400 -#define NGX_HTTP_PROPPATCH 0x0800 -#define NGX_HTTP_LOCK 0x1000 -#define NGX_HTTP_UNLOCK 0x2000 -#define NGX_HTTP_PATCH 0x4000 -#define NGX_HTTP_TRACE 0x8000 +#define NGX_HTTP_UNKNOWN 0x00000001 +#define NGX_HTTP_GET 0x00000002 +#define NGX_HTTP_HEAD 0x00000004 +#define NGX_HTTP_POST 0x00000008 +#define NGX_HTTP_PUT 0x00000010 +#define NGX_HTTP_DELETE 0x00000020 +#define NGX_HTTP_MKCOL 0x00000040 +#define NGX_HTTP_COPY 0x00000080 +#define NGX_HTTP_MOVE 0x00000100 +#define NGX_HTTP_OPTIONS 0x00000200 +#define NGX_HTTP_PROPFIND 0x00000400 +#define NGX_HTTP_PROPPATCH 0x00000800 +#define NGX_HTTP_LOCK 0x00001000 +#define NGX_HTTP_UNLOCK 0x00002000 +#define NGX_HTTP_PATCH 0x00004000 +#define NGX_HTTP_TRACE 0x00008000 +#define NGX_HTTP_CONNECT 0x00010000 #define NGX_HTTP_CONNECTION_CLOSE 1 #define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 @@ -301,6 +302,9 @@ typedef struct { ngx_chain_t *busy; ngx_http_chunked_t *chunked; ngx_http_client_body_handler_pt post_handler; + unsigned filter_need_buffering:1; + unsigned last_sent:1; + unsigned last_saved:1; } ngx_http_request_body_t; @@ -467,9 +471,6 @@ struct ngx_http_request_s { /* URI with "+" */ unsigned plus_in_uri:1; - /* URI with " " */ - unsigned space_in_uri:1; - /* URI with empty path */ unsigned empty_path_in_uri:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index 0cae88f..ad3549f 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -62,11 +62,16 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, /* * set by ngx_pcalloc(): * + * rb->temp_file = NULL; * rb->bufs = NULL; * rb->buf = NULL; * rb->free = NULL; * rb->busy = NULL; * rb->chunked = NULL; + * rb->received = 0; + * rb->filter_need_buffering = 0; + * rb->last_sent = 0; + * rb->last_saved = 0; */ rb->rest = -1; @@ -144,7 +149,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, } } - if (rb->rest == 0) { + if (rb->rest == 0 && rb->last_saved) { /* the whole request body was pre-read */ r->request_body_no_buffering = 0; post_handler(r); @@ -172,6 +177,10 @@ ngx_http_read_client_request_body(ngx_http_request_t *r, size += preread; } + if (size == 0) { + size++; + } + } else { size = clcf->client_body_buffer_size; } @@ -270,6 +279,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) 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; @@ -277,12 +287,17 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) c = r->connection; rb = r->request_body; + flush = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { for ( ;; ) { + if (rb->rest == 0) { + break; + } + if (rb->buf->last == rb->buf->end) { /* update chains */ @@ -306,12 +321,25 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) 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; } @@ -323,6 +351,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) 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, @@ -347,6 +379,7 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) /* pass buffer to request body filter chain */ + flush = 0; out.buf = rb->buf; out.next = NULL; @@ -368,11 +401,19 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body rest %O", rb->rest); - if (rb->rest == 0) { + if (flush) { + rc = ngx_http_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { break; } - if (!c->read->ready) { + 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); @@ -939,15 +980,32 @@ ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http request body content length filter"); rb->rest = r->headers_in.content_length_n; - } - out = NULL; - ll = &out; + if (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; + ll = &tl->next; + } + } for (cl = in; cl; cl = cl->next) { @@ -1011,6 +1069,9 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb = r->request_body; + out = NULL; + ll = &out; + if (rb->rest == -1) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1027,9 +1088,6 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in) rb->rest = cscf->large_client_header_buffers.size; } - out = NULL; - ll = &out; - for (cl = in; cl; cl = cl->next) { b = NULL; @@ -1186,15 +1244,16 @@ ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) { ngx_buf_t *b; - ngx_chain_t *cl; + ngx_chain_t *cl, *tl, **ll; ngx_http_request_body_t *rb; rb = r->request_body; -#if (NGX_DEBUG) + ll = &rb->bufs; + + for (cl = rb->bufs; cl; cl = cl->next) { #if 0 - for (cl = rb->bufs; cl; cl = cl->next) { ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body old buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1203,10 +1262,13 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); - } #endif + ll = &cl->next; + } + for (cl = in; cl; cl = cl->next) { + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, "http body new buf t:%d f:%d %p, pos %p, size: %z " "file: %O, size: %O", @@ -1215,15 +1277,31 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) cl->buf->last - cl->buf->pos, cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); + + if (cl->buf->last_buf) { + + if (rb->last_saved) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "duplicate last buf in save filter"); + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->last_saved = 1; + } + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + *ll = NULL; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; } -#endif - - /* TODO: coalesce neighbouring buffers */ - - if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + *ll = NULL; if (r->request_body_no_buffering) { return NGX_OK; @@ -1231,7 +1309,7 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) if (rb->rest > 0) { - if (rb->buf && rb->buf->last == rb->buf->end + if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end && ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -1240,10 +1318,18 @@ ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in) return NGX_OK; } - /* rb->rest == 0 */ + if (!rb->last_saved) { + return NGX_OK; + } if (rb->temp_file || r->request_body_in_file_only) { + if (rb->bufs && rb->bufs->buf->in_file) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "body already in file"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (ngx_http_write_request_body(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 13c57d6..bebdbd9 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -250,7 +250,7 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) cv = (ngx_http_complex_value_t **) (p + cmd->offset); - if (*cv != NULL) { + if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) { return "is duplicate"; } @@ -275,6 +275,44 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } +char * +ngx_http_set_complex_value_zero_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_http_compile_complex_value_t ccv; + + cv = (ngx_http_complex_value_t **) (p + cmd->offset); + + if (*cv != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + ccv.zero = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + char * ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index a6b345e..4360038 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -216,6 +216,8 @@ size_t ngx_http_complex_value_size(ngx_http_request_t *r, ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_http_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index b682af5..ded833c 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -187,6 +187,8 @@ static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, static void ngx_http_upstream_ssl_save_session(ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); +static ngx_int_t ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -1509,8 +1511,9 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; r->connection->log->action = "connecting to upstream"; @@ -1597,10 +1600,12 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + u->writer.out = NULL; u->writer.last = &u->writer.out; u->writer.connection = c; - u->writer.limit = 0; + u->writer.limit = clcf->sendfile_max_chunk; if (u->request_sent) { if (ngx_http_upstream_reinit(r, u) != NGX_OK) { @@ -1681,9 +1686,6 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, return; } - c->sendfile = 0; - u->output.sendfile = 0; - if (u->conf->ssl_server_name || u->conf->ssl_verify) { if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, @@ -1692,6 +1694,16 @@ 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 (ngx_http_upstream_ssl_certificate(r, u, c) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + if (u->conf->ssl_session_reuse) { c->ssl->save_session = ngx_http_upstream_ssl_save_session; @@ -1779,6 +1791,11 @@ ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, } } + if (!c->ssl->sendfile) { + c->sendfile = 0; + u->output.sendfile = 0; + } + c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; @@ -1912,6 +1929,45 @@ done: return NGX_OK; } + +static ngx_int_t +ngx_http_upstream_ssl_certificate(ngx_http_request_t *r, + ngx_http_upstream_t *u, ngx_connection_t *c) +{ + ngx_str_t cert, key; + + if (ngx_http_complex_value(r, u->conf->ssl_certificate, &cert) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl cert: \"%s\"", cert.data); + + if (*cert.data == '\0') { + return NGX_OK; + } + + if (ngx_http_complex_value(r, u->conf->ssl_certificate_key, &key) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key, + u->conf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + #endif @@ -3791,6 +3847,7 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) { ngx_str_t name; ngx_event_pipe_t *p; + ngx_connection_t *c; ngx_thread_pool_t *tp; ngx_http_request_t *r; ngx_http_core_loc_conf_t *clcf; @@ -3798,6 +3855,27 @@ ngx_http_upstream_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) r = file->thread_ctx; p = r->upstream->pipe; + if (r->aio) { + /* + * tolerate sendfile() calls if another operation is already + * running; this can happen due to subrequests, multiple calls + * of the next body filter from a filter, or in HTTP/2 due to + * a write event on the main connection + */ + + c = r->connection; + +#if (NGX_HTTP_V2) + if (r->stream) { + c = r->stream->connection->connection; + } +#endif + + if (task == c->sendfile_task) { + return NGX_OK; + } + } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); tp = clcf->thread_pool; @@ -3849,6 +3927,20 @@ ngx_http_upstream_thread_event_handler(ngx_event_t *ev) r->main->blocked--; r->aio = 0; +#if (NGX_HTTP_V2) + + if (r->stream) { + /* + * for HTTP/2, update write event to make sure processing will + * reach the main connection to handle sendfile() in threads + */ + + c->write->ready = 1; + c->write->active = 0; + } + +#endif + if (r->done) { /* * trigger connection event handler if the subrequest was diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index fd642c2..3db7b06 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -234,6 +234,10 @@ typedef struct { ngx_http_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; ngx_flag_t ssl_verify; + + ngx_http_complex_value_t *ssl_certificate; + ngx_http_complex_value_t *ssl_certificate_key; + ngx_array_t *ssl_passwords; #endif ngx_str_t module; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c index 6a5d957..932f26d 100644 --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -321,18 +321,13 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate); if (delay > 0) { - limit = 0; c->write->delayed = 1; ngx_add_timer(c->write, delay); } } - if (limit - && c->write->ready - && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize)) - { - c->write->delayed = 1; - ngx_add_timer(c->write, 1); + if (chain && c->write->ready && !c->write->delayed) { + ngx_post_event(c->write, &ngx_posted_next_events); } for (cl = r->out; cl && cl != chain; /* void */) { diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index 3611a2e..0e45a7b 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -173,7 +173,7 @@ 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); + 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); static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); @@ -1140,9 +1140,10 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->payload_bytes += size; if (r->request_body) { - rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); + rc = ngx_http_v2_process_request_body(r, pos, size, + stream->in_closed, 0); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; ngx_http_finalize_request(r, rc); } @@ -1599,10 +1600,10 @@ ngx_http_v2_state_field_huff(ngx_http_v2_connection_t *h2c, u_char *pos, h2c->state.length -= size; h2c->state.field_rest -= size; - if (ngx_http_v2_huff_decode(&h2c->state.field_state, pos, size, - &h2c->state.field_end, - h2c->state.field_rest == 0, - h2c->connection->log) + if (ngx_http_huff_decode(&h2c->state.field_state, pos, size, + &h2c->state.field_end, + h2c->state.field_rest == 0, + h2c->connection->log) != NGX_OK) { ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, @@ -3457,7 +3458,7 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header) continue; } - if (ch == '\0' || ch == LF || ch == CR || ch == ':' + if (ch <= 0x20 || ch == 0x7f || ch == ':' || (ch >= 'A' && ch <= 'Z')) { ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, @@ -3606,7 +3607,8 @@ ngx_http_v2_parse_method(ngx_http_request_t *r, ngx_str_t *value) { 4, "LOCK", NGX_HTTP_LOCK }, { 6, "UNLOCK", NGX_HTTP_UNLOCK }, { 5, "PATCH", NGX_HTTP_PATCH }, - { 5, "TRACE", NGX_HTTP_TRACE } + { 5, "TRACE", NGX_HTTP_TRACE }, + { 7, "CONNECT", NGX_HTTP_CONNECT } }, *test; if (r->method_name.len) { @@ -4026,16 +4028,30 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) return NGX_OK; } + rb->rest = 1; + + /* set rb->filter_need_buffering */ + + rc = ngx_http_top_request_body_filter(r, NULL); + + if (rc != NGX_OK) { + stream->skip_data = 1; + return rc; + } + h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); len = r->headers_in.content_length_n; - if (r->request_body_no_buffering && !stream->in_closed) { + if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { + len = clcf->client_body_buffer_size; - if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { - len = clcf->client_body_buffer_size; - } + } else { + len++; + } + + if (r->request_body_no_buffering || rb->filter_need_buffering) { /* * We need a room to store data up to the stream's initial window size, @@ -4049,57 +4065,54 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) if (len > NGX_HTTP_V2_MAX_WINDOW) { len = NGX_HTTP_V2_MAX_WINDOW; } - - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size - && !r->request_body_in_file_only) - { - rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); - - } else { - rb->buf = ngx_calloc_buf(r->pool); - - if (rb->buf != NULL) { - rb->buf->sync = 1; - } } + rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + if (rb->buf == NULL) { stream->skip_data = 1; return NGX_HTTP_INTERNAL_SERVER_ERROR; } - rb->rest = 1; - buf = stream->preread; if (stream->in_closed) { - r->request_body_no_buffering = 0; + if (!rb->filter_need_buffering) { + r->request_body_no_buffering = 0; + } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 1); + buf->last - buf->pos, 1, 0); ngx_pfree(r->pool, buf->start); + + } else { + rc = ngx_http_v2_process_request_body(r, NULL, 0, 1, 0); + } + + if (rc != NGX_AGAIN) { return rc; } - return ngx_http_v2_process_request_body(r, NULL, 0, 1); + r->read_event_handler = ngx_http_v2_read_client_request_body_handler; + r->write_event_handler = ngx_http_request_empty_handler; + + return NGX_AGAIN; } if (buf) { rc = ngx_http_v2_process_request_body(r, buf->pos, - buf->last - buf->pos, 0); + buf->last - buf->pos, 0, 0); ngx_pfree(r->pool, buf->start); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } } - if (r->request_body_no_buffering) { + if (r->request_body_no_buffering || rb->filter_need_buffering) { size = (size_t) len - h2scf->preread_size; } else { @@ -4141,9 +4154,9 @@ ngx_http_v2_read_request_body(ngx_http_request_t *r) 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) + size_t size, ngx_uint_t last, ngx_uint_t flush) { - ngx_buf_t *buf; + size_t n; ngx_int_t rc; ngx_connection_t *fc; ngx_http_request_body_t *rb; @@ -4151,77 +4164,122 @@ ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, fc = r->connection; rb = r->request_body; - buf = rb->buf; - if (size) { - if (buf->sync) { - buf->pos = buf->start = pos; - buf->last = buf->end = pos + size; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 process request body"); - r->request_body_in_file_only = 1; + if (size == 0 && !last && !flush) { + return NGX_AGAIN; + } - } else { - if (size > (size_t) (buf->end - buf->last)) { - ngx_log_error(NGX_LOG_INFO, fc->log, 0, - "client intended to send body data " - "larger than declared"); + for ( ;; ) { + for ( ;; ) { + if (rb->buf->last == rb->buf->end && size) { - return NGX_HTTP_BAD_REQUEST; + if (r->request_body_no_buffering) { + + /* should never happen due to flow control */ + + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "no space in http2 body buffer"); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + /* update chains */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 body update chains"); + + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + if (rb->busy != NULL) { + ngx_log_error(NGX_LOG_ALERT, fc->log, 0, + "busy buffers after request body flush"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; } - buf->last = ngx_cpymem(buf->last, pos, size); + /* copy body data to the buffer */ + + n = rb->buf->end - rb->buf->last; + + if (n > size) { + n = size; + } + + if (n > 0) { + rb->buf->last = ngx_cpymem(rb->buf->last, pos, n); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body recv %uz", n); + + pos += n; + size -= n; + + if (size == 0 && last) { + rb->rest = 0; + } + + if (size == 0) { + break; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 request body rest %O", rb->rest); + + if (flush) { + rc = ngx_http_v2_filter_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + } + + if (rb->rest == 0 && rb->last_saved) { + break; + } + + if (size == 0) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_add_timer(fc->read, clcf->client_body_timeout); + + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + + return NGX_AGAIN; } } - if (last) { - rb->rest = 0; - - if (fc->read->timer_set) { - ngx_del_timer(fc->read); - } - - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); - return NGX_OK; - } - - rc = ngx_http_v2_filter_request_body(r); - - if (rc != NGX_OK) { - return rc; - } - - if (buf->sync) { - /* prevent reusing this buffer in the upstream module */ - rb->buf = NULL; - } - - if (r->headers_in.chunked) { - r->headers_in.content_length_n = rb->received; - } - - r->read_event_handler = ngx_http_block_reading; - rb->post_handler(r); - - return NGX_OK; + if (fc->read->timer_set) { + ngx_del_timer(fc->read); } - if (size == 0) { - return NGX_OK; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - if (r->request_body_no_buffering) { - ngx_post_event(fc->read, &ngx_posted_events); + if (!flush) { + ngx_post_event(fc->read, &ngx_posted_events); + } + return NGX_OK; } - if (buf->sync) { - return ngx_http_v2_filter_request_body(r); + if (r->headers_in.chunked) { + r->headers_in.content_length_n = rb->received; } + r->read_event_handler = ngx_http_block_reading; + rb->post_handler(r); + return NGX_OK; } @@ -4238,7 +4296,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) rb = r->request_body; buf = rb->buf; - if (buf->pos == buf->last && rb->rest) { + if (buf->pos == buf->last && (rb->rest || rb->last_sent)) { cl = NULL; goto update; } @@ -4301,6 +4359,7 @@ ngx_http_v2_filter_request_body(ngx_http_request_t *r) } b->last_buf = 1; + rb->last_sent = 1; } b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body; @@ -4320,7 +4379,12 @@ update: static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) { - ngx_connection_t *fc; + size_t window; + ngx_buf_t *buf; + ngx_int_t rc; + ngx_connection_t *fc; + ngx_http_v2_stream_t *stream; + ngx_http_v2_connection_t *h2c; fc = r->connection; @@ -4346,6 +4410,75 @@ ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; } + + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); + + if (rc != NGX_OK && rc != NGX_AGAIN) { + r->stream->skip_data = 1; + ngx_http_finalize_request(r, rc); + return; + } + + if (rc == NGX_OK) { + return; + } + + if (r->stream->no_flow_control) { + return; + } + + if (r->request_body->rest == 0) { + return; + } + + if (r->request_body->busy != NULL) { + return; + } + + stream = r->stream; + h2c = stream->connection; + + buf = r->request_body->buf; + + buf->pos = buf->start; + buf->last = buf->start; + + window = buf->end - buf->start; + + if (h2c->state.stream == stream) { + window -= h2c->state.length; + } + + if (window <= stream->recv_window) { + if (window < stream->recv_window) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "http2 negative window update"); + + stream->skip_data = 1; + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (ngx_http_v2_send_window_update(h2c, stream->node->id, + window - stream->recv_window) + == NGX_ERROR) + { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + stream->recv_window = window; + + if (ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { + stream->skip_data = 1; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } } @@ -4358,11 +4491,13 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) ngx_connection_t *fc; ngx_http_v2_stream_t *stream; ngx_http_v2_connection_t *h2c; - ngx_http_core_loc_conf_t *clcf; stream = r->stream; fc = r->connection; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 read unbuffered request body"); + if (fc->read->timedout) { if (stream->recv_window) { stream->skip_data = 1; @@ -4379,17 +4514,21 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - rc = ngx_http_v2_filter_request_body(r); + rc = ngx_http_v2_process_request_body(r, NULL, 0, r->stream->in_closed, 1); - if (rc != NGX_OK) { + if (rc != NGX_OK && rc != NGX_AGAIN) { stream->skip_data = 1; return rc; } - if (!r->request_body->rest) { + if (rc == NGX_OK) { return NGX_OK; } + if (r->request_body->rest == 0) { + return NGX_AGAIN; + } + if (r->request_body->busy != NULL) { return NGX_AGAIN; } @@ -4430,11 +4569,6 @@ ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (stream->recv_window == 0) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_add_timer(fc->read, clcf->client_body_timeout); - } - stream->recv_window = window; return NGX_AGAIN; diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index 3492297..70ee287 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -13,8 +13,7 @@ #include -#define NGX_HTTP_V2_ALPN_ADVERTISE "\x02h2" -#define NGX_HTTP_V2_NPN_ADVERTISE NGX_HTTP_V2_ALPN_ADVERTISE +#define NGX_HTTP_V2_ALPN_PROTO "\x02h2" #define NGX_HTTP_V2_STATE_BUFFER_SIZE 16 @@ -312,12 +311,6 @@ ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c, ngx_int_t ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size); -ngx_int_t ngx_http_v2_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_v2_huff_encode(u_char *src, size_t len, u_char *dst, - ngx_uint_t lower); - - #define ngx_http_v2_prefix(bits) ((1 << (bits)) - 1) diff --git a/src/http/v2/ngx_http_v2_encode.c b/src/http/v2/ngx_http_v2_encode.c index ac79208..8798aa9 100644 --- a/src/http/v2/ngx_http_v2_encode.c +++ b/src/http/v2/ngx_http_v2_encode.c @@ -20,7 +20,7 @@ ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, { size_t hlen; - hlen = ngx_http_v2_huff_encode(src, len, tmp, lower); + hlen = ngx_http_huff_encode(src, len, tmp, lower); if (hlen > 0) { *dst = NGX_HTTP_V2_ENCODE_HUFF; diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index a6e5e7d..9ffb155 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -1432,6 +1432,9 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) size = 0; #endif + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, + "http2 send chain: %p", in); + while (in) { size = ngx_buf_size(in->buf); @@ -1450,12 +1453,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) return NGX_CHAIN_ERROR; } - if (stream->queued) { - fc->write->active = 1; - fc->write->ready = 0; - - } else { - fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; } return NULL; @@ -1464,9 +1463,16 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) h2c = stream->connection; if (size && ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { - fc->write->active = 1; - fc->write->ready = 0; - return in; + + if (ngx_http_v2_filter_send(fc, stream) == NGX_ERROR) { + return NGX_CHAIN_ERROR; + } + + if (ngx_http_v2_flow_control(h2c, stream) == NGX_DECLINED) { + fc->write->active = 1; + fc->write->ready = 0; + return in; + } } if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_filter_get_shadow) { @@ -1809,6 +1815,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) { + fc->buffered &= ~NGX_HTTP_V2_BUFFERED; + return NGX_OK; + } + stream->blocked = 1; if (ngx_http_v2_send_output_queue(stream->connection) == NGX_ERROR) { diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h index b865a3b..e0c62b7 100644 --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -115,6 +115,8 @@ typedef struct { ngx_msec_t timeout; ngx_msec_t resolver_timeout; + ngx_uint_t max_errors; + ngx_str_t server_name; u_char *file_name; @@ -231,14 +233,15 @@ typedef struct { ngx_uint_t command; ngx_array_t args; + ngx_uint_t errors; ngx_uint_t login_attempt; /* used to parse POP3/IMAP/SMTP command */ ngx_uint_t state; + u_char *tag_start; u_char *cmd_start; u_char *arg_start; - u_char *arg_end; ngx_uint_t literal_len; } ngx_mail_session_t; @@ -321,6 +324,7 @@ typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s); struct ngx_mail_protocol_s { ngx_str_t name; + ngx_str_t alpn; in_port_t port[4]; ngx_uint_t type; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c index 2a198f4..27f64b9 100644 --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1137,8 +1137,8 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, ngx_str_t login, passwd; ngx_connection_t *c; #if (NGX_MAIL_SSL) - ngx_str_t verify, subject, issuer, serial, fingerprint, - raw_cert, cert; + ngx_str_t protocol, cipher, verify, subject, issuer, + serial, fingerprint, raw_cert, cert; ngx_mail_ssl_conf_t *sslcf; #endif ngx_mail_core_srv_conf_t *cscf; @@ -1155,6 +1155,25 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, #if (NGX_MAIL_SSL) + if (c->ssl) { + + if (ngx_ssl_get_protocol(c, pool, &protocol) != NGX_OK) { + return NULL; + } + + protocol.len = ngx_strlen(protocol.data); + + if (ngx_ssl_get_cipher_name(c, pool, &cipher) != NGX_OK) { + return NULL; + } + + cipher.len = ngx_strlen(cipher.data); + + } else { + ngx_str_null(&protocol); + ngx_str_null(&cipher); + } + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (c->ssl && sslcf->verify) { @@ -1252,6 +1271,10 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, if (c->ssl) { len += sizeof("Auth-SSL: on" CRLF) - 1 + + sizeof("Auth-SSL-Protocol: ") - 1 + protocol.len + + sizeof(CRLF) - 1 + + sizeof("Auth-SSL-Cipher: ") - 1 + cipher.len + + sizeof(CRLF) - 1 + sizeof("Auth-SSL-Verify: ") - 1 + verify.len + sizeof(CRLF) - 1 + sizeof("Auth-SSL-Subject: ") - 1 + subject.len @@ -1373,6 +1396,20 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool, b->last = ngx_cpymem(b->last, "Auth-SSL: on" CRLF, sizeof("Auth-SSL: on" CRLF) - 1); + if (protocol.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Protocol: ", + sizeof("Auth-SSL-Protocol: ") - 1); + b->last = ngx_copy(b->last, protocol.data, protocol.len); + *b->last++ = CR; *b->last++ = LF; + } + + if (cipher.len) { + b->last = ngx_cpymem(b->last, "Auth-SSL-Cipher: ", + sizeof("Auth-SSL-Cipher: ") - 1); + b->last = ngx_copy(b->last, cipher.data, cipher.len); + *b->last++ = CR; *b->last++ = LF; + } + if (verify.len) { b->last = ngx_cpymem(b->last, "Auth-SSL-Verify: ", sizeof("Auth-SSL-Verify: ") - 1); diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c index 4083124..115671c 100644 --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -85,6 +85,13 @@ static ngx_command_t ngx_mail_core_commands[] = { offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), NULL }, + { ngx_string("max_errors"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, max_errors), + NULL }, + ngx_null_command }; @@ -163,6 +170,8 @@ ngx_mail_core_create_srv_conf(ngx_conf_t *cf) cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; + cscf->max_errors = NGX_CONF_UNSET_UINT; + cscf->resolver = NGX_CONF_UNSET_PTR; cscf->file_name = cf->conf_file->file.name.data; @@ -182,6 +191,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, 30000); + ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c index 0aaa0e7..246ba97 100644 --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -833,20 +833,23 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) ngx_str_t l; ngx_mail_core_srv_conf_t *cscf; - n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); + if (s->buffer->last < s->buffer->end) { - if (n == NGX_ERROR || n == 0) { - ngx_mail_close_connection(c); - return NGX_ERROR; - } + n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last); - if (n > 0) { - s->buffer->last += n; - } + if (n == NGX_ERROR || n == 0) { + ngx_mail_close_connection(c); + return NGX_ERROR; + } - if (n == NGX_AGAIN) { - if (s->buffer->pos == s->buffer->last) { - return NGX_AGAIN; + if (n > 0) { + s->buffer->last += n; + } + + if (n == NGX_AGAIN) { + if (s->buffer->pos == s->buffer->last) { + return NGX_AGAIN; + } } } @@ -871,7 +874,20 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c) return NGX_MAIL_PARSE_INVALID_COMMAND; } - if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { + + s->errors++; + + if (s->errors >= cscf->max_errors) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too many invalid commands"); + s->quit = 1; + } + + return rc; + } + + if (rc == NGX_IMAP_NEXT) { return rc; } diff --git a/src/mail/ngx_mail_imap_handler.c b/src/mail/ngx_mail_imap_handler.c index 5dfdd76..291e87a 100644 --- a/src/mail/ngx_mail_imap_handler.c +++ b/src/mail/ngx_mail_imap_handler.c @@ -101,10 +101,9 @@ ngx_mail_imap_init_protocol(ngx_event_t *rev) void ngx_mail_imap_auth_state(ngx_event_t *rev) { - u_char *p, *dst, *src, *end; - ngx_str_t *arg; + u_char *p; ngx_int_t rc; - ngx_uint_t tag, i; + ngx_uint_t tag; ngx_connection_t *c; ngx_mail_session_t *s; @@ -158,27 +157,6 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i", s->command); - if (s->backslash) { - - arg = s->args.elts; - - for (i = 0; i < s->args.nelts; i++) { - dst = arg[i].data; - end = dst + arg[i].len; - - for (src = dst; src < end; dst++) { - *dst = *src; - if (*src++ == '\\') { - *dst = *src++; - } - } - - arg[i].len = dst - arg[i].data; - } - - s->backslash = 0; - } - switch (s->mail_state) { case ngx_imap_start: @@ -248,6 +226,10 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) ngx_str_set(&s->out, imap_next); } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -297,13 +279,14 @@ ngx_mail_imap_auth_state(ngx_event_t *rev) if (s->state) { /* preserve tag */ - s->arg_start = s->buffer->start + s->tag.len; - s->buffer->pos = s->arg_start; - s->buffer->last = s->arg_start; + s->arg_start = s->buffer->pos; } else { - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } + s->tag.len = 0; } } @@ -481,6 +464,8 @@ ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c) if (c->ssl == NULL) { sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; c->read->handler = ngx_mail_starttls_handler; return NGX_OK; } diff --git a/src/mail/ngx_mail_imap_module.c b/src/mail/ngx_mail_imap_module.c index 1f187fd..02c684c 100644 --- a/src/mail/ngx_mail_imap_module.c +++ b/src/mail/ngx_mail_imap_module.c @@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_imap_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_imap_protocol = { ngx_string("imap"), + ngx_string("\x04imap"), { 143, 993, 0, 0 }, NGX_MAIL_IMAP_PROTOCOL, diff --git a/src/mail/ngx_mail_parse.c b/src/mail/ngx_mail_parse.c index 2c2cdff..4db1f18 100644 --- a/src/mail/ngx_mail_parse.c +++ b/src/mail/ngx_mail_parse.c @@ -21,6 +21,8 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) ngx_str_t *arg; enum { sw_start = 0, + sw_command, + sw_invalid, sw_spaces_before_argument, sw_argument, sw_almost_done @@ -35,8 +37,14 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) /* POP3 command */ case sw_start: + s->cmd_start = p; + state = sw_command; + + /* fall through */ + + case sw_command: if (ch == ' ' || ch == CR || ch == LF) { - c = s->buffer->start; + c = s->cmd_start; if (p - c == 4) { @@ -85,6 +93,9 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -104,16 +115,17 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) break; + case sw_invalid: + goto invalid; + case sw_spaces_before_argument: switch (ch) { case ' ': break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 2) { @@ -188,37 +200,39 @@ ngx_mail_pop3_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; - s->arg_start = NULL; + s->state = sw_invalid; - return NGX_MAIL_PARSE_INVALID_COMMAND; + /* skip invalid command till LF */ + + for ( /* void */ ; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s) { - u_char ch, *p, *c; + u_char ch, *p, *c, *dst, *src, *end; ngx_str_t *arg; enum { sw_start = 0, + sw_tag, + sw_invalid, sw_spaces_before_command, sw_command, sw_spaces_before_argument, @@ -241,31 +255,45 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) /* IMAP tag */ case sw_start: + s->tag_start = p; + state = sw_tag; + + /* fall through */ + + case sw_tag: switch (ch) { case ' ': - s->tag.len = p - s->buffer->start + 1; - s->tag.data = s->buffer->start; + s->tag.len = p - s->tag_start + 1; + s->tag.data = s->tag_start; state = sw_spaces_before_command; break; case CR: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; case LF: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; + goto invalid; + default: + if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z') + && (ch < '0' || ch > '9') && ch != '-' && ch != '.' + && ch != '_') + { + goto invalid; + } + if (p - s->tag_start > 31) { + goto invalid; + } + break; } break; + case sw_invalid: + goto invalid; + case sw_spaces_before_command: switch (ch) { case ' ': break; case CR: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; case LF: - s->state = sw_start; - return NGX_MAIL_PARSE_INVALID_COMMAND; + goto invalid; default: s->cmd_start = p; state = sw_command; @@ -385,6 +413,9 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) goto invalid; } + s->cmd.data = s->cmd_start; + s->cmd.len = p - s->cmd_start; + switch (ch) { case ' ': state = sw_spaces_before_argument; @@ -410,10 +441,8 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; case '"': if (s->args.nelts <= 2) { @@ -460,6 +489,22 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) } arg->len = p - s->arg_start; arg->data = s->arg_start; + + if (s->backslash) { + dst = s->arg_start; + end = p; + + for (src = dst; src < end; dst++) { + *dst = *src; + if (*src++ == '\\') { + *dst = *src++; + } + } + + arg->len = dst - s->arg_start; + s->backslash = 0; + } + s->arg_start = NULL; switch (ch) { @@ -588,34 +633,46 @@ ngx_mail_imap_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - - s->arg_start = NULL; - s->cmd_start = NULL; - s->quoted = 0; - s->no_sync_literal = 0; - s->literal_len = 0; - } - s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; return NGX_OK; invalid: - s->state = sw_start; + s->state = sw_invalid; s->quoted = 0; + s->backslash = 0; s->no_sync_literal = 0; s->literal_len = 0; - return NGX_MAIL_PARSE_INVALID_COMMAND; + /* skip invalid command till LF */ + + for ( /* void */ ; p < s->buffer->last; p++) { + if (*p == LF) { + s->state = sw_start; + s->buffer->pos = p + 1; + + /* detect non-synchronizing literals */ + + if ((size_t) (p - s->buffer->start) > sizeof("{1+}") - 1) { + p--; + + if (*p == CR) { + p--; + } + + if (*p == '}' && *(p - 1) == '+') { + s->quit = 1; + } + } + + return NGX_MAIL_PARSE_INVALID_COMMAND; + } + } + + s->buffer->pos = p; + + return NGX_AGAIN; } @@ -758,10 +815,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) break; case CR: state = sw_almost_done; - s->arg_end = p; break; case LF: - s->arg_end = p; goto done; default: if (s->args.nelts <= 10) { @@ -821,17 +876,6 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s) done: s->buffer->pos = p + 1; - - if (s->arg_start) { - arg = ngx_array_push(&s->args); - if (arg == NULL) { - return NGX_ERROR; - } - arg->len = s->arg_end - s->arg_start; - arg->data = s->arg_start; - s->arg_start = NULL; - } - s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; return NGX_OK; @@ -839,21 +883,20 @@ done: invalid: s->state = sw_invalid; - s->arg_start = NULL; /* skip invalid command till LF */ - for (p = s->buffer->pos; p < s->buffer->last; p++) { + for ( /* void */ ; p < s->buffer->last; p++) { if (*p == LF) { s->state = sw_start; - p++; - break; + s->buffer->pos = p + 1; + return NGX_MAIL_PARSE_INVALID_COMMAND; } } s->buffer->pos = p; - return NGX_MAIL_PARSE_INVALID_COMMAND; + return NGX_AGAIN; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c index edfd986..226e741 100644 --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -262,6 +262,10 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) } } + if (s->buffer->pos < s->buffer->last) { + s->blocked = 1; + } + switch (rc) { case NGX_DONE: @@ -283,11 +287,14 @@ ngx_mail_pop3_auth_state(ngx_event_t *rev) case NGX_OK: s->args.nelts = 0; - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; + + if (s->buffer->pos == s->buffer->last) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + } if (s->state) { - s->arg_start = s->buffer->start; + s->arg_start = s->buffer->pos; } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { @@ -400,6 +407,8 @@ ngx_mail_pop3_stls(ngx_mail_session_t *s, ngx_connection_t *c) if (c->ssl == NULL) { sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->starttls) { + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; c->read->handler = ngx_mail_starttls_handler; return NGX_OK; } diff --git a/src/mail/ngx_mail_pop3_module.c b/src/mail/ngx_mail_pop3_module.c index a673070..a257b5a 100644 --- a/src/mail/ngx_mail_pop3_module.c +++ b/src/mail/ngx_mail_pop3_module.c @@ -46,6 +46,7 @@ static ngx_str_t ngx_mail_pop3_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_pop3_protocol = { ngx_string("pop3"), + ngx_string("\x04pop3"), { 110, 995, 0, 0 }, NGX_MAIL_POP3_PROTOCOL, diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c index 66aa0ba..a7ab077 100644 --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -327,6 +327,10 @@ 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) { + ngx_post_event(c->write, &ngx_posted_events); + } + ngx_mail_proxy_handler(s->connection->write); return; @@ -482,6 +486,10 @@ 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) { + ngx_post_event(c->write, &ngx_posted_events); + } + ngx_mail_proxy_handler(s->connection->write); return; @@ -813,13 +821,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev) c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - if (s->buffer->pos == s->buffer->last) { - ngx_mail_proxy_handler(s->connection->write); - - } else { - ngx_mail_proxy_handler(c->write); + if (s->buffer->pos < s->buffer->last) { + ngx_post_event(c->write, &ngx_posted_events); } + ngx_mail_proxy_handler(s->connection->write); + return; default: diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c index 3b5a2d8..0e05fdc 100644 --- a/src/mail/ngx_mail_smtp_module.c +++ b/src/mail/ngx_mail_smtp_module.c @@ -39,6 +39,7 @@ static ngx_str_t ngx_mail_smtp_auth_methods_names[] = { static ngx_mail_protocol_t ngx_mail_smtp_protocol = { ngx_string("smtp"), + ngx_string("\x04smtp"), { 25, 465, 587, 0 }, NGX_MAIL_SMTP_PROTOCOL, diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index 7eae83e..2a1043e 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -14,6 +14,12 @@ #define NGX_DEFAULT_ECDH_CURVE "auto" +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); +#endif + 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); @@ -244,6 +250,54 @@ ngx_module_t ngx_mail_ssl_module = { static ngx_str_t ngx_mail_ssl_sess_id_ctx = ngx_string("MAIL"); +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + +static int +ngx_mail_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; + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; +#if (NGX_DEBUG) + unsigned int i; +#endif + + c = ngx_ssl_get_connection(ssl_conn); + s = c->data; + +#if (NGX_DEBUG) + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); + } +#endif + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + srv = cscf->protocol->alpn.data; + srvlen = cscf->protocol->alpn.len; + + if (SSL_select_next_proto((unsigned char **) out, outlen, srv, srvlen, + in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, + "SSL ALPN selected: %*s", (size_t) *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + static void * ngx_mail_ssl_create_conf(ngx_conf_t *cf) { @@ -394,6 +448,17 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL); +#endif + + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, conf->certificate_keys, conf->passwords) != NGX_OK) @@ -430,13 +495,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h index 74b8b7f..fcab2d6 100644 --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -38,6 +38,39 @@ typedef volatile ngx_atomic_uint_t ngx_atomic_t; #define ngx_cpu_pause() +#elif (NGX_HAVE_GCC_ATOMIC) + +/* GCC 4.1 builtin atomic operations */ + +#define NGX_HAVE_ATOMIC_OPS 1 + +typedef long ngx_atomic_int_t; +typedef unsigned long ngx_atomic_uint_t; + +#if (NGX_PTR_SIZE == 8) +#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) +#else +#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) +#endif + +typedef volatile ngx_atomic_uint_t ngx_atomic_t; + + +#define ngx_atomic_cmp_set(lock, old, set) \ + __sync_bool_compare_and_swap(lock, old, set) + +#define ngx_atomic_fetch_add(value, add) \ + __sync_fetch_and_add(value, add) + +#define ngx_memory_barrier() __sync_synchronize() + +#if ( __i386__ || __i386 || __amd64__ || __amd64 ) +#define ngx_cpu_pause() __asm__ ("pause") +#else +#define ngx_cpu_pause() +#endif + + #elif (NGX_DARWIN_ATOMIC) /* @@ -88,39 +121,6 @@ typedef uint32_t ngx_atomic_uint_t; typedef volatile ngx_atomic_uint_t ngx_atomic_t; -#elif (NGX_HAVE_GCC_ATOMIC) - -/* GCC 4.1 builtin atomic operations */ - -#define NGX_HAVE_ATOMIC_OPS 1 - -typedef long ngx_atomic_int_t; -typedef unsigned long ngx_atomic_uint_t; - -#if (NGX_PTR_SIZE == 8) -#define NGX_ATOMIC_T_LEN (sizeof("-9223372036854775808") - 1) -#else -#define NGX_ATOMIC_T_LEN (sizeof("-2147483648") - 1) -#endif - -typedef volatile ngx_atomic_uint_t ngx_atomic_t; - - -#define ngx_atomic_cmp_set(lock, old, set) \ - __sync_bool_compare_and_swap(lock, old, set) - -#define ngx_atomic_fetch_add(value, add) \ - __sync_fetch_and_add(value, add) - -#define ngx_memory_barrier() __sync_synchronize() - -#if ( __i386__ || __i386 || __amd64__ || __amd64 ) -#define ngx_cpu_pause() __asm__ ("pause") -#else -#define ngx_cpu_pause() -#endif - - #elif ( __i386__ || __i386 ) typedef int32_t ngx_atomic_int_t; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c index 3d415bd..5c6a830 100644 --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -32,23 +32,22 @@ ngx_chain_t * ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { - int rc, flags; - off_t send, prev_send, sent; - size_t file_size; - ssize_t n; - ngx_uint_t eintr, eagain; - ngx_err_t err; - ngx_buf_t *file; - ngx_event_t *wev; - ngx_chain_t *cl; - ngx_iovec_t header, trailer; - struct sf_hdtr hdtr; - struct iovec headers[NGX_IOVS_PREALLOCATE]; - struct iovec trailers[NGX_IOVS_PREALLOCATE]; -#if (NGX_HAVE_AIO_SENDFILE) - ngx_uint_t ebusy; - ngx_event_aio_t *aio; + int rc, flags; + off_t send, prev_send, sent; + size_t file_size; + ssize_t n; + ngx_err_t err; + ngx_buf_t *file; + ngx_uint_t eintr, eagain; +#if (NGX_HAVE_SENDFILE_NODISKIO) + ngx_uint_t ebusy; #endif + ngx_event_t *wev; + ngx_chain_t *cl; + ngx_iovec_t header, trailer; + struct sf_hdtr hdtr; + struct iovec headers[NGX_IOVS_PREALLOCATE]; + struct iovec trailers[NGX_IOVS_PREALLOCATE]; wev = c->write; @@ -77,11 +76,6 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eagain = 0; flags = 0; -#if (NGX_HAVE_AIO_SENDFILE && NGX_SUPPRESS_WARN) - aio = NULL; - file = NULL; -#endif - header.iovs = headers; header.nalloc = NGX_IOVS_PREALLOCATE; @@ -90,7 +84,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) for ( ;; ) { eintr = 0; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) ebusy = 0; #endif prev_send = send; @@ -179,9 +173,14 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) sent = 0; -#if (NGX_HAVE_AIO_SENDFILE) - aio = file->file->aio; - flags = (aio && aio->preload_handler) ? SF_NODISKIO : 0; +#if (NGX_HAVE_SENDFILE_NODISKIO) + + flags = (c->busy_count <= 2) ? SF_NODISKIO : 0; + + if (file->file->directio) { + flags |= SF_NOCACHE; + } + #endif rc = sendfile(file->file->fd, c->fd, file->file_pos, @@ -199,7 +198,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) eintr = 1; break; -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) case NGX_EBUSY: ebusy = 1; break; @@ -252,54 +251,30 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) in = ngx_chain_update_sent(in, sent); -#if (NGX_HAVE_AIO_SENDFILE) +#if (NGX_HAVE_SENDFILE_NODISKIO) if (ebusy) { - if (aio->event.active) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - if (sent) { - c->busy_count = 0; - } - - return in; - } - if (sent == 0) { c->busy_count++; - if (c->busy_count > 2) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "sendfile(%V) returned busy again", - &file->file->name); - - c->busy_count = 0; - aio->preload_handler = NULL; - - send = prev_send; - continue; - } + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "sendfile() busy, count:%d", c->busy_count); } else { c->busy_count = 0; } - n = aio->preload_handler(file); - - if (n > 0) { - send = prev_send + sent; - continue; + if (wev->posted) { + ngx_delete_posted_event(wev); } + ngx_post_event(wev, &ngx_posted_next_events); + + wev->ready = 0; return in; } - if (flags == SF_NODISKIO) { - c->busy_count = 0; - } + c->busy_count = 0; #endif diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c index 5695839..101d91a 100644 --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -38,6 +38,9 @@ static void ngx_linux_sendfile_thread_handler(void *data, ngx_log_t *log); * On Linux up to 2.6.16 sendfile() does not allow to pass the count parameter * more than 2G-1 bytes even on 64-bit platforms: it returns EINVAL, * so we limit it to 2G-1 bytes. + * + * On Linux 2.6.16 and later, sendfile() silently limits the count parameter + * to 2G minus the page size, even on 64-bit platforms. */ #define NGX_SENDFILE_MAXSIZE 2147483647L @@ -216,7 +219,6 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) */ send = prev_send + sent; - continue; } if (send >= limit || in == NULL) { @@ -377,15 +379,6 @@ ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size) return ctx->sent; } - if (task->event.active && ctx->file == file) { - /* - * tolerate duplicate calls; they can happen due to subrequests - * or multiple calls of the next body filter from a filter - */ - - return NGX_DONE; - } - ctx->file = file; ctx->socket = c->fd; ctx->size = size; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index b31485f..07cd05e 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -398,6 +398,8 @@ ngx_pass_open_channel(ngx_cycle_t *cycle) ngx_int_t i; ngx_channel_t ch; + ngx_memzero(&ch, sizeof(ngx_channel_t)); + ch.command = NGX_CMD_OPEN_CHANNEL; ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c index a3577ce..b1ae4b5 100644 --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -96,7 +96,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain, off_t limit) iov->iov_len += n; } else { - if (vec.nelts >= IOV_MAX) { + if (vec.nelts == vec.nalloc) { break; } diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c index 7835675..3304c84 100644 --- a/src/stream/ngx_stream.c +++ b/src/stream/ngx_stream.c @@ -510,6 +510,10 @@ ngx_stream_optimize_servers(ngx_conf_t *cf, ngx_array_t *ports) 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 diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h index 9e35832..46c3622 100644 --- a/src/stream/ngx_stream.h +++ b/src/stream/ngx_stream.h @@ -65,6 +65,9 @@ typedef struct { int backlog; int rcvbuf; int sndbuf; +#if (NGX_HAVE_TCP_FASTOPEN) + int fastopen; +#endif int type; } ngx_stream_listen_t; diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c index 9b6afe9..d96d27a 100644 --- a/src/stream/ngx_stream_core_module.c +++ b/src/stream/ngx_stream_core_module.c @@ -615,6 +615,10 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ls->type = SOCK_STREAM; ls->ctx = cf->ctx; +#if (NGX_HAVE_TCP_FASTOPEN) + ls->fastopen = -1; +#endif + #if (NGX_HAVE_INET6) ls->ipv6only = 1; #endif @@ -635,6 +639,21 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) continue; } +#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; + + if (ls->fastopen == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid fastopen \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } +#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; @@ -859,6 +878,12 @@ ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (ls->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 } als = cmcf->listen.elts; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index 01cda7a..934e7d8 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -31,6 +31,7 @@ typedef struct { ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; ngx_flag_t proxy_protocol; + ngx_flag_t half_close; ngx_stream_upstream_local_t *local; ngx_flag_t socket_keepalive; @@ -46,8 +47,8 @@ typedef struct { ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; - ngx_str_t ssl_certificate; - ngx_str_t ssl_certificate_key; + ngx_stream_complex_value_t *ssl_certificate; + ngx_stream_complex_value_t *ssl_certificate_key; ngx_array_t *ssl_passwords; ngx_array_t *ssl_conf_commands; @@ -101,6 +102,7 @@ static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s); 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_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); @@ -244,6 +246,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = { offsetof(ngx_stream_proxy_srv_conf_t, proxy_protocol), NULL }, + { ngx_string("proxy_half_close"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, half_close), + NULL }, + #if (NGX_STREAM_SSL) { ngx_string("proxy_ssl"), @@ -318,14 +327,14 @@ static ngx_command_t ngx_stream_proxy_commands[] = { { ngx_string("proxy_ssl_certificate"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_zero_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate), NULL }, { ngx_string("proxy_ssl_certificate_key"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_stream_set_complex_value_zero_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_certificate_key), NULL }, @@ -1060,6 +1069,15 @@ 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 (ngx_stream_proxy_ssl_certificate(s) != NGX_OK) { + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + } + if (pscf->ssl_session_reuse) { pc->ssl->save_session = ngx_stream_proxy_ssl_save_session; @@ -1247,6 +1265,50 @@ done: return NGX_OK; } + +static ngx_int_t +ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s) +{ + ngx_str_t cert, key; + ngx_connection_t *c; + ngx_stream_proxy_srv_conf_t *pscf; + + c = s->upstream->peer.connection; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + if (ngx_stream_complex_value(s, pscf->ssl_certificate, &cert) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream upstream ssl cert: \"%s\"", cert.data); + + if (*cert.data == '\0') { + return NGX_OK; + } + + if (ngx_stream_complex_value(s, pscf->ssl_certificate_key, &key) + != NGX_OK) + { + return NGX_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, + "stream upstream ssl key: \"%s\"", key.data); + + if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key, + pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + + return NGX_OK; +} + #endif @@ -1701,6 +1763,24 @@ ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, } if (dst) { + + if (dst->type == SOCK_STREAM && pscf->half_close + && src->read->eof && !u->half_closed && !dst->buffered) + { + if (ngx_shutdown_socket(dst->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_connection_error(c, ngx_socket_errno, + ngx_shutdown_socket_n " failed"); + + ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); + return; + } + + u->half_closed = 1; + ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, + "stream proxy %s socket shutdown", + from_upstream ? "client" : "upstream"); + } + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR); return; @@ -1779,6 +1859,13 @@ ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, return NGX_DECLINED; } + if (pscf->half_close) { + /* avoid closing live connections until both read ends get EOF */ + if (!(c->read->eof && pc->read->eof && !c->buffered && !pc->buffered)) { + return NGX_DECLINED; + } + } + handler = c->log->handler; c->log->handler = NULL; @@ -1977,14 +2064,9 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) * * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; - * conf->ssl_name = NULL; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; - * conf->ssl_certificate = { 0, NULL }; - * conf->ssl_certificate_key = { 0, NULL }; * - * conf->upload_rate = NULL; - * conf->download_rate = NULL; * conf->ssl = NULL; * conf->upstream = NULL; * conf->upstream_value = NULL; @@ -1994,6 +2076,8 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->timeout = NGX_CONF_UNSET_MSEC; conf->next_upstream_timeout = NGX_CONF_UNSET_MSEC; conf->buffer_size = NGX_CONF_UNSET_SIZE; + conf->upload_rate = NGX_CONF_UNSET_PTR; + conf->download_rate = NGX_CONF_UNSET_PTR; conf->requests = NGX_CONF_UNSET_UINT; conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; @@ -2001,13 +2085,17 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf) conf->proxy_protocol = NGX_CONF_UNSET; conf->local = NGX_CONF_UNSET_PTR; conf->socket_keepalive = NGX_CONF_UNSET; + conf->half_close = NGX_CONF_UNSET; #if (NGX_STREAM_SSL) conf->ssl_enable = NGX_CONF_UNSET; conf->ssl_session_reuse = NGX_CONF_UNSET; + conf->ssl_name = NGX_CONF_UNSET_PTR; conf->ssl_server_name = NGX_CONF_UNSET; conf->ssl_verify = NGX_CONF_UNSET; conf->ssl_verify_depth = NGX_CONF_UNSET_UINT; + conf->ssl_certificate = NGX_CONF_UNSET_PTR; + conf->ssl_certificate_key = NGX_CONF_UNSET_PTR; conf->ssl_passwords = NGX_CONF_UNSET_PTR; conf->ssl_conf_commands = NGX_CONF_UNSET_PTR; #endif @@ -2034,13 +2122,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 16384); - if (conf->upload_rate == NULL) { - conf->upload_rate = prev->upload_rate; - } + ngx_conf_merge_ptr_value(conf->upload_rate, prev->upload_rate, NULL); - if (conf->download_rate == NULL) { - conf->download_rate = prev->download_rate; - } + ngx_conf_merge_ptr_value(conf->download_rate, prev->download_rate, NULL); ngx_conf_merge_uint_value(conf->requests, prev->requests, 0); @@ -2060,6 +2144,8 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->socket_keepalive, prev->socket_keepalive, 0); + ngx_conf_merge_value(conf->half_close, prev->half_close, 0); + #if (NGX_STREAM_SSL) ngx_conf_merge_value(conf->ssl_enable, prev->ssl_enable, 0); @@ -2073,9 +2159,7 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); - if (conf->ssl_name == NULL) { - conf->ssl_name = prev->ssl_name; - } + ngx_conf_merge_ptr_value(conf->ssl_name, prev->ssl_name, NULL); ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0); @@ -2089,11 +2173,11 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, ""); - ngx_conf_merge_str_value(conf->ssl_certificate, - prev->ssl_certificate, ""); + ngx_conf_merge_ptr_value(conf->ssl_certificate, + prev->ssl_certificate, NULL); - ngx_conf_merge_str_value(conf->ssl_certificate_key, - prev->ssl_certificate_key, ""); + ngx_conf_merge_ptr_value(conf->ssl_certificate_key, + prev->ssl_certificate_key, NULL); ngx_conf_merge_ptr_value(conf->ssl_passwords, prev->ssl_passwords, NULL); @@ -2137,27 +2221,41 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) cln->handler = ngx_ssl_cleanup_ctx; cln->data = pscf->ssl; - if (pscf->ssl_certificate.len) { - - if (pscf->ssl_certificate_key.len == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "no \"proxy_ssl_certificate_key\" is defined " - "for certificate \"%V\"", &pscf->ssl_certificate); - return NGX_ERROR; - } - - if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate, - &pscf->ssl_certificate_key, pscf->ssl_passwords) - != NGX_OK) - { - return NGX_ERROR; - } - } - if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, 0) != NGX_OK) { return NGX_ERROR; } + if (pscf->ssl_certificate) { + + if (pscf->ssl_certificate_key == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"proxy_ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &pscf->ssl_certificate->value); + return NGX_ERROR; + } + + if (pscf->ssl_certificate->lengths + || pscf->ssl_certificate_key->lengths) + { + pscf->ssl_passwords = + ngx_ssl_preserve_passwords(cf, pscf->ssl_passwords); + if (pscf->ssl_passwords == NULL) { + return NGX_ERROR; + } + + } else { + if (ngx_ssl_certificate(cf, pscf->ssl, + &pscf->ssl_certificate->value, + &pscf->ssl_certificate_key->value, + pscf->ssl_passwords) + != NGX_OK) + { + return NGX_ERROR; + } + } + } + if (pscf->ssl_verify) { if (pscf->ssl_trusted_certificate.len == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c index a15f772..c447e15 100644 --- a/src/stream/ngx_stream_script.c +++ b/src/stream/ngx_stream_script.c @@ -252,7 +252,7 @@ ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, cv = (ngx_stream_complex_value_t **) (p + cmd->offset); - if (*cv != NULL) { + if (*cv != NGX_CONF_UNSET_PTR && *cv != NULL) { return "is duplicate"; } @@ -277,6 +277,44 @@ ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, } +char * +ngx_stream_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_str_t *value; + ngx_stream_complex_value_t **cv; + ngx_stream_compile_complex_value_t ccv; + + cv = (ngx_stream_complex_value_t **) (p + cmd->offset); + + if (*cv != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + *cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); + if (*cv == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = *cv; + ccv.zero = 1; + + if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + char * ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/stream/ngx_stream_script.h b/src/stream/ngx_stream_script.h index a481ca3..d8f3740 100644 --- a/src/stream/ngx_stream_script.h +++ b/src/stream/ngx_stream_script.h @@ -112,6 +112,8 @@ ngx_int_t ngx_stream_compile_complex_value( ngx_stream_compile_complex_value_t *ccv); char *ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +char *ngx_stream_set_complex_value_zero_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); char *ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index d8c0471..c530832 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -23,7 +23,13 @@ static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg); +static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, + void *arg); +#endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation +static int ngx_stream_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, + const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg); #endif #ifdef SSL_R_CERT_CB_ERROR static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg); @@ -45,6 +51,8 @@ static char *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); +static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); @@ -211,6 +219,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = { offsetof(ngx_stream_ssl_conf_t, conf_commands), &ngx_stream_ssl_conf_command_post }, + { ngx_string("ssl_alpn"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE, + ngx_stream_ssl_alpn, + NGX_STREAM_SRV_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -254,6 +269,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_ciphers"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_ciphers, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curve"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_curve, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_curves"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_STREAM_VAR_CHANGEABLE, 0 }, @@ -266,6 +284,9 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_alpn_protocol"), NULL, ngx_stream_ssl_variable, + (uintptr_t) ngx_ssl_get_alpn_protocol, NGX_STREAM_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 }, @@ -434,7 +455,7 @@ ngx_stream_ssl_handshake_handler(ngx_connection_t *c) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME -int +static int ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { return SSL_TLSEXT_ERR_OK; @@ -443,9 +464,49 @@ ngx_stream_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + +static int +ngx_stream_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) +{ + ngx_str_t *alpn; +#if (NGX_DEBUG) + unsigned int i; + ngx_connection_t *c; + + c = ngx_ssl_get_connection(ssl_conn); + + for (i = 0; i < inlen; i += in[i] + 1) { + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL ALPN supported by client: %*s", + (size_t) in[i], &in[i + 1]); + } + +#endif + + alpn = arg; + + if (SSL_select_next_proto((unsigned char **) out, outlen, alpn->data, + alpn->len, in, inlen) + != OPENSSL_NPN_NEGOTIATED) + { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0, + "SSL ALPN selected: %*s", (size_t) *outlen, *out); + + return SSL_TLSEXT_ERR_OK; +} + +#endif + + #ifdef SSL_R_CERT_CB_ERROR -int +static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg) { ngx_str_t cert, key; @@ -602,6 +663,7 @@ ngx_stream_ssl_create_conf(ngx_conf_t *cf) * 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; */ @@ -660,6 +722,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->trusted_certificate, prev->trusted_certificate, ""); ngx_conf_merge_str_value(conf->crl, prev->crl, ""); + ngx_conf_merge_str_value(conf->alpn, prev->alpn, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, NGX_DEFAULT_ECDH_CURVE); @@ -720,6 +783,20 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_stream_ssl_servername); #endif +#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation + if (conf->alpn.len) { + SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_stream_ssl_alpn_select, + &conf->alpn); + } +#endif + + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + conf->prefer_server_ciphers) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -752,13 +829,6 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - if (conf->verify) { if (conf->client_certificate.len == 0 && conf->verify != 3) { @@ -1056,6 +1126,60 @@ invalid: } +static char * +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; + + u_char *p; + size_t len; + ngx_str_t *value; + ngx_uint_t i; + + if (scf->alpn.len) { + return "is duplicate"; + } + + value = cf->args->elts; + + len = 0; + + for (i = 1; i < cf->args->nelts; i++) { + + if (value[i].len > 255) { + return "protocol too long"; + } + + len += value[i].len + 1; + } + + scf->alpn.data = ngx_pnalloc(cf->pool, len); + if (scf->alpn.data == NULL) { + return NGX_CONF_ERROR; + } + + p = scf->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; + + return NGX_CONF_OK; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl_alpn\" directive requires OpenSSL " + "with ALPN support"); + return NGX_CONF_ERROR; +#endif +} + + static char * ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) { diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index c6e24be..e7c825e 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -42,6 +42,7 @@ typedef struct { ngx_str_t client_certificate; ngx_str_t trusted_certificate; ngx_str_t crl; + ngx_str_t alpn; ngx_str_t ciphers; diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h index 9857e0b..f561779 100644 --- a/src/stream/ngx_stream_upstream.h +++ b/src/stream/ngx_stream_upstream.h @@ -142,6 +142,7 @@ typedef struct { ngx_stream_upstream_state_t *state; unsigned connected:1; unsigned proxy_protocol:1; + unsigned half_closed:1; } ngx_stream_upstream_t; From 24d9bd02907266424ef4a74ad7de298be7723631 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:20:28 -0400 Subject: [PATCH 197/414] Update changelog --- debian/changelog | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b9b5b7..98db79b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,9 @@ -nginx (1.20.2-3) UNRELEASED; urgency=medium +nginx (1.22.0-1) UNRELEASED; urgency=medium - * d/conf/mime.types: Fix a typo in font/woff2 extension in - mime.types. (Closes: #1010798) + * New upstream release (1.22.0) + * Additional changes: + * d/conf/mime.types: Fix a typo in font/woff2 extension in + mime.types. (Closes: #1010798) -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 From 5900bc832a071308bdd1b10ae01796389fbf4e7b Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 24 May 2022 14:24:29 -0400 Subject: [PATCH 198/414] Changelog update --- debian/changelog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/debian/changelog b/debian/changelog index 98db79b..04b3aa1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,11 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * Additional changes: * d/conf/mime.types: Fix a typo in font/woff2 extension in mime.types. (Closes: #1010798) + * d/upstream/signing-key.asc: Additional signing keys observed + in upstream (Konstantin Pavlov ) during + upstream merge/import by Thomas Ward, additional signing key + was added to the keyring while keeping Maxim's key in signing + keys as wel. -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 From c394d8d99931a56d9a37543e2673caf7b321e8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 07:01:01 +0200 Subject: [PATCH 199/414] d/p/CVE-2021-3618.patch removed, fix is included in new upstream release --- debian/changelog | 5 ++ debian/patches/CVE-2021-3618.patch | 84 ------------------------------ debian/patches/series | 1 - 3 files changed, 5 insertions(+), 85 deletions(-) delete mode 100644 debian/patches/CVE-2021-3618.patch diff --git a/debian/changelog b/debian/changelog index 04b3aa1..16e6b2d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium + [ Thomas Ward ] * New upstream release (1.22.0) * Additional changes: * d/conf/mime.types: Fix a typo in font/woff2 extension in @@ -10,6 +11,10 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium was added to the keyring while keeping Maxim's key in signing keys as wel. + [ Jan Mojžíš ] + * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream + release + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 nginx (1.20.2-2) unstable; urgency=medium diff --git a/debian/patches/CVE-2021-3618.patch b/debian/patches/CVE-2021-3618.patch deleted file mode 100644 index 10f37a9..0000000 --- a/debian/patches/CVE-2021-3618.patch +++ /dev/null @@ -1,84 +0,0 @@ -Subject: Patch mitigation for CVE-2021-3618 - Mail: max_errors directive. - . - Similarly to smtpd_hard_error_limit in Postfix and smtp_max_unknown_commands - in Exim, specifies the number of errors after which the connection is closed. -Origin: upstream, http://hg.nginx.org/nginx/rev/ec1071830799 -Bug-Debian: https://bugs.debian.org/991328 - ---- a/src/mail/ngx_mail.h -+++ b/src/mail/ngx_mail.h -@@ -115,6 +115,8 @@ - ngx_msec_t timeout; - ngx_msec_t resolver_timeout; - -+ ngx_uint_t max_errors; -+ - ngx_str_t server_name; - - u_char *file_name; -@@ -231,6 +233,7 @@ - ngx_uint_t command; - ngx_array_t args; - -+ ngx_uint_t errors; - ngx_uint_t login_attempt; - - /* used to parse POP3/IMAP/SMTP command */ ---- a/src/mail/ngx_mail_core_module.c -+++ b/src/mail/ngx_mail_core_module.c -@@ -85,6 +85,13 @@ - offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), - NULL }, - -+ { ngx_string("max_errors"), -+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, -+ ngx_conf_set_num_slot, -+ NGX_MAIL_SRV_CONF_OFFSET, -+ offsetof(ngx_mail_core_srv_conf_t, max_errors), -+ NULL }, -+ - ngx_null_command - }; - -@@ -163,6 +170,8 @@ - cscf->timeout = NGX_CONF_UNSET_MSEC; - cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; - -+ cscf->max_errors = NGX_CONF_UNSET_UINT; -+ - cscf->resolver = NGX_CONF_UNSET_PTR; - - cscf->file_name = cf->conf_file->file.name.data; -@@ -182,6 +191,7 @@ - ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, - 30000); - -+ ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5); - - ngx_conf_merge_str_value(conf->server_name, prev->server_name, ""); - ---- a/src/mail/ngx_mail_handler.c -+++ b/src/mail/ngx_mail_handler.c -@@ -871,7 +871,20 @@ - return NGX_MAIL_PARSE_INVALID_COMMAND; - } - -- if (rc == NGX_IMAP_NEXT || rc == NGX_MAIL_PARSE_INVALID_COMMAND) { -+ if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { -+ -+ s->errors++; -+ -+ if (s->errors >= cscf->max_errors) { -+ ngx_log_error(NGX_LOG_INFO, c->log, 0, -+ "client sent too many invalid commands"); -+ s->quit = 1; -+ } -+ -+ return rc; -+ } -+ -+ if (rc == NGX_IMAP_NEXT) { - return rc; - } - diff --git a/debian/patches/series b/debian/patches/series index 4e43575..5b6b799 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,3 +1,2 @@ 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch -CVE-2021-3618.patch From 7224e5e7ca7a1a8bd6f692082b176830ae3657bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 11:04:30 +0200 Subject: [PATCH 200/414] d/control: removed ppc64el from list of luajit platforms. --- debian/changelog | 1 + debian/control | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 16e6b2d..eb42d36 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release + * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/control b/debian/control index cc32589..3a2b586 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From a013b18ff66b9ac1d899827ed5725589f9900701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 11:19:06 +0200 Subject: [PATCH 201/414] d/changelog fix whitespaces --- debian/changelog | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/changelog b/debian/changelog index eb42d36..713a937 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Thomas Ward ] * New upstream release (1.22.0) * Additional changes: - * d/conf/mime.types: Fix a typo in font/woff2 extension in + * d/conf/mime.types: Fix a typo in font/woff2 extension in mime.types. (Closes: #1010798) * d/upstream/signing-key.asc: Additional signing keys observed in upstream (Konstantin Pavlov ) during @@ -21,7 +21,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium nginx (1.20.2-2) unstable; urgency=medium [ Thomas Ward ] - * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX + * d/patches/CVE-2021-3618.patch: Include upstream changeset from NGINX that adds mitigations into the Mail module for CVE-2021-3618.patch. (Closes: #991328) @@ -46,7 +46,7 @@ nginx (1.20.2-1) unstable; urgency=medium * d/conf/mime.types: Update mime.types to more match upstream mime.types and include upstream changes with mime.types from 1.21.x via nginx.org mercurial repository versions. - * d/control: Remove self from Uploaders per other Debian devs, who want + * d/control: Remove self from Uploaders per other Debian devs, who want that commit to be done by someone on the current uploaders/maintainers group instead. @@ -65,7 +65,7 @@ nginx (1.18.0-9) unstable; urgency=medium * d/watch: Update watch syntax to match all even versions of NGINX releases rather than use a watch syntax that is static to one specific version. This will fix the untracked "New upstream stable versions" problem. - * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in + * d/control: Update 'uploaders' as Thomas Ward is now a maintainer in the Salsa repository. -- Jan Mojžíš Tue, 05 Apr 2022 19:11:47 +0200 From 5eec971e2717232ed1d8a88ce193edccb495e582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 17:13:14 +0200 Subject: [PATCH 202/414] d/copyright: - bump nginx copyright years - added copyright for src/stream/ngx_stream_set_module.c --- debian/changelog | 2 ++ debian/copyright | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 713a937..53399e7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,8 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) + * d/copyright: bump nginx copyright years + * d/copyright: added copyright for src/stream/ngx_stream_set_module.c -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/copyright b/debian/copyright index f82fc2d..a3f59eb 100644 --- a/debian/copyright +++ b/debian/copyright @@ -3,8 +3,8 @@ Upstream-Name: nginx Source: https://nginx.org/en/download.html Files: * -Copyright: 2002-2019, Igor Sysoev - 2011-2019, Nginx, Inc. +Copyright: 2002-2021, Igor Sysoev + 2011-2022, Nginx, Inc. Maxim Dounin Valentin V. Bartenev Roman Arutyunyan @@ -15,6 +15,11 @@ Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby License: BSD-2-clause +Files: src/stream/ngx_stream_set_module.c +Copyright: Copyright (C) Pavel Pautov + Copyright (C) Nginx, Inc. +License: BSD-2-clause + Files: src/http/modules/ngx_http_scgi_module.c src/http/modules/ngx_http_uwsgi_module.c Copyright: 2009-2010, Unbit S.a.s. From c3f9fc730b23255d7b2fce09b34a98583f9dcfc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Wed, 25 May 2022 17:45:49 +0200 Subject: [PATCH 203/414] d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c --- debian/changelog | 1 + debian/copyright | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/debian/changelog b/debian/changelog index 53399e7..1c01d3f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,6 +17,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c + * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 diff --git a/debian/copyright b/debian/copyright index a3f59eb..d5c191a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -28,12 +28,6 @@ Copyright: 2009-2010, Unbit S.a.s. Nginx, Inc. License: BSD-2-clause -Files: src/http/v2/ngx_http_v2_huff_encode.c -Copyright: 2015, Vlad Krasnov - Nginx, Inc. - Valentin V. Bartenev -License: BSD-2-clause - Files: contrib/geo2nginx.pl Copyright: 2005, Andrei Nigmatulin License: BSD-2-clause From a8ebc4ba0c136b1df2c7bd2effffa467dc821f0d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Thu, 26 May 2022 23:15:02 -0400 Subject: [PATCH 204/414] Update d/copyright for murmurhash license being public-domain --- debian/changelog | 5 ++++- debian/copyright | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 1c01d3f..4874df2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,7 +9,10 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium in upstream (Konstantin Pavlov ) during upstream merge/import by Thomas Ward, additional signing key was added to the keyring while keeping Maxim's key in signing - keys as wel. + keys as well. + * d/copyright: Updated copyright for src/core/ngx_murmurhash.c + and debian/modules/http-ndk/src/hash/murmurhash2.c to be + public-domain (Closes: #1011936) [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/copyright b/debian/copyright index d5c191a..59dfc09 100644 --- a/debian/copyright +++ b/debian/copyright @@ -13,7 +13,10 @@ License: BSD-2-clause Files: src/core/ngx_murmurhash.c Copyright: Copyright (C) Austin Appleby -License: BSD-2-clause +License: public-domain + All MurmurHash versions are public domain software, and the author + disclaims all copyright to their code. + Files: src/stream/ngx_stream_set_module.c Copyright: Copyright (C) Pavel Pautov @@ -65,7 +68,9 @@ License: BSD-4-clause Files: debian/modules/http-ndk/src/hash/murmurhash2.c Copyright: Austin Appleby -License: BSD-3-clause +License: public-domain + All MurmurHash versions are public domain software, and the author + disclaims all copyright to their code. Files: debian/modules/http-auth-pam/* Copyright: 2008-2020, Sergio Talens Oliag From 20eb8ab414656c56632795454156ce014532972d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 8 Jun 2022 15:22:49 -0400 Subject: [PATCH 205/414] ppc64el FTBFS fixed in luajit, nginx: no action needed --- debian/changelog | 1 - debian/control | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4874df2..3b92437 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,7 +17,6 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream release - * d/control: removed ppc64el from list of luajit platforms. (Closes: #1011303) * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c diff --git a/debian/control b/debian/control index 3a2b586..cc32589 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From 4b7212e74500151248dab2f0baf45837e39a266d Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Wed, 8 Jun 2022 16:15:40 -0400 Subject: [PATCH 206/414] Enable luajit for s390x --- debian/changelog | 5 +++++ debian/control | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3b92437..48897b5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,11 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: Updated copyright for src/core/ngx_murmurhash.c and debian/modules/http-ndk/src/hash/murmurhash2.c to be public-domain (Closes: #1011936) + * d/control: Use libluajit-5.1-dev for s390x. + Due to src:luajit2 landing in Unstable, superseding src:luajit, + and due to luajit2 having s390x support, we can use s390x now + with luajit instead of standard Lua. + Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/control b/debian/control index cc32589..bbec75a 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el !s390x], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From 333875401c6fa18c4f37d39f6ea6411ef1e1b60a Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sat, 25 Jun 2022 17:31:16 -0400 Subject: [PATCH 207/414] Return ppc64el to liblua, luajit2 still broken on ppc64el. --- debian/changelog | 2 ++ debian/control | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 48897b5..fec8e1d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,8 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium and due to luajit2 having s390x support, we can use s390x now with luajit instead of standard Lua. Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. + * d/control: Use liblua for ppc64el - src:luajit2 is still not ppc64el + stable and there seems to be nobody willing to support it. [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream diff --git a/debian/control b/debian/control index bbec75a..5ae14c8 100644 --- a/debian/control +++ b/debian/control @@ -12,8 +12,8 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !ppc64el !s390x], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 ppc64el s390x], + liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !s390x], + libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, From d4b9d6a1daf9e64816e6d69d4d10083a032e251c Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 4 Feb 2022 00:00:41 +0800 Subject: [PATCH 208/414] Adding nginx-dev package for tools for building out-of-tree modules Nginx does not officially provide a mechanism to build out-of-tree modules, however, this can be achieved by using all the headers and the configure scripts in the auto/ directory. As a result, a nginx-dev package can thus be developed for build out-of-tree modules. The detailed steps to build an out-of-tree module in the headers-only nginx source tree is: 1. Execute the configure script of nginx, with the same configure arguments (excluding the reference to other dynamic modules, but including the reference to depending modules as a built-in module). To prevent the configure scripts modifying the nginx ource tree, we can 1. point the build dir to a directory elsewhere, to generate all the build time files outside; 2. slightly patch the configure scripts to prevent generating a makefile directly in the source tree, which simply includes the generated makefile at the build dir. 2. Execute make at the source tree, but providing the generated makefile in the build dir. The command is `make -C /path/to/nginx/source -f /path/to/build_dir/Makefile modules` To make sure the compiled module is compatible with the nginx binary and the nginx binaries with the same upstream version, the key points are: - Module signature: A module signature containing the (upstream) version number and encoding the necessary configuration flags is put in each module as well as the nginx binary itself. When loading a module, nginx will compare the signature on the module with its own. As long as the configure flags, especially those encoded in the signature, and the version of the nginx source used to build the module are the same as thoes used to build the nginx binary, the moudle can pass the signature check. As a result, the module can depend on the exact nginx upstream version, ignoring the debian revison. - ABI compatibility: We should maintain nginx precisely, to prevent making any ABI changes between different debian revisions. - Build check: When building the module, we can perform a simple module loading check via `nginx -t`. This test serves as a "smoking test", to ensure we are actually building loadable modules. Summing all the above up and adding the necessary automation scripts for module packaging, the nginx-dev package can be composed, including the following parts: - The headers and configure scripts: generated and filtered out from the source tree. The scripts are slightly patched to prevent generating a makefile directly in the source tree, as stated above; - The recorded configure options: all the modules built should include these options when configured; - dh_nginx script and its man page: modified from the original dh_nginx script, adding a "--in-nginx-tree" option. When specified, the behavior remains the same as the original version (so the option is added in the rule building the in-package modules). When not specified, the dependency added into misc:Depends will be the exact upstream nginx version, ignoring the debian revision. E.g. nginx-common >= 1.20.2, << 1.20.2.1~ - a debhelper sequence plugin which can be enabled by module packages with `dh --with=nginx`, inserting `dh_nginx` after `dh_install` - a build system plugin which can bu enabled by module packages with `dh --buildsystem=nginx_mod`, automating the module building process using the steps mentioned before. - autoscript templates used by dh_nginx are also installed without modification. Currently. the architecture of nginx-dev is any because nginx has arch related dependencies, which is brought in by http-lua module. After it is removed from the nginx source tree, the architecture can be changed to all since no binary is included in this package. --- debian/control | 13 +++++ debian/debhelper/nginx.pm | 8 +++ debian/debhelper/nginx_mod.pm | 96 +++++++++++++++++++++++++++++++++++ debian/dh_nginx | 18 ++++++- debian/nginx-dev.install | 8 +++ debian/nginx-dev.manpages | 1 + debian/rules | 31 ++++++++--- 7 files changed, 165 insertions(+), 10 deletions(-) create mode 100644 debian/debhelper/nginx.pm create mode 100644 debian/debhelper/nginx_mod.pm create mode 100644 debian/nginx-dev.install create mode 100644 debian/nginx-dev.manpages diff --git a/debian/control b/debian/control index 5ae14c8..9f31ba4 100644 --- a/debian/control +++ b/debian/control @@ -68,6 +68,19 @@ Description: small, powerful, scalable web/proxy server - common files This package contains base configuration files used by all versions of nginx. +Package: nginx-dev +Architecture: any +Depends: ${misc:Depends}, ${S:Build-Depends}, + nginx-core (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}) +Description: nginx web/proxy server - development headers + Nginx ("engine X") is a high-performance web and reverse proxy server + created by Igor Sysoev. It can be used both as a standalone web server + and as a proxy to reduce the load on back-end HTTP or mail servers. + . + This package provides development headers and necessary config scripts + for the nginx web/proxy server, useful to develop and link third party + additions to the Debian nginx web/proxy server packages. + Package: nginx-core Architecture: any Depends: libnginx-mod-http-geoip (= ${binary:Version}), diff --git a/debian/debhelper/nginx.pm b/debian/debhelper/nginx.pm new file mode 100644 index 0000000..0473815 --- /dev/null +++ b/debian/debhelper/nginx.pm @@ -0,0 +1,8 @@ +#!/usr/bin/perl +use warnings; +use strict; +use Debian::Debhelper::Dh_Lib; + +insert_after("dh_install", "dh_nginx"); + +1; diff --git a/debian/debhelper/nginx_mod.pm b/debian/debhelper/nginx_mod.pm new file mode 100644 index 0000000..af37fda --- /dev/null +++ b/debian/debhelper/nginx_mod.pm @@ -0,0 +1,96 @@ +# A build system class for handling nginx modules. +# +# Copyright: © 2022 Miao Wang +# License: MIT + +package Debian::Debhelper::Buildsystem::nginx_mod; + +use strict; +use warnings; +use Debian::Debhelper::Dh_Lib qw(error doit); +use File::Spec; +use parent qw(Debian::Debhelper::Buildsystem::makefile); +use Config; + +sub DESCRIPTION { + "Nginx Module (config)" +} + +sub check_auto_buildable { + my ($this, $step) = @_; + + return 1 if -e $this->get_sourcepath("config"); +} + +sub _NGINX_SRC_DIR { + "/usr/share/nginx/src" +} + +sub new { + my $class=shift; + my $this= $class->SUPER::new(@_); + $this->prefer_out_of_source_building(@_); + return $this; +} + +sub configure { + my $this=shift; + + doit({ + "chdir" => $this->_NGINX_SRC_DIR, + "update_env" => { + "src_dir" => $this->get_sourcedir, + "bld_dir" => $this->get_builddir, + "pwd_dir" => $this->{cwd}, + }, + }, "bash", "-c", '. ./conf_flags + ./configure \\ + --with-cc-opt="$(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get CFLAGS) -fPIC $(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get CPPFLAGS)" \\ + --with-ld-opt="$(cd "$pwd_dir/$src_dir"; dpkg-buildflags --get LDFLAGS) -fPIC" \\ + "${NGX_CONF_FLAGS[@]}" \\ + --add-dynamic-module="$pwd_dir/$src_dir" \\ + --builddir="$pwd_dir/$bld_dir" \\ + "$@"', "dummy", @_); +} + +sub build { + my $this=shift; + + $this->do_make("-f", File::Spec->catfile($this->{cwd}, $this->get_buildpath("Makefile")), "-C", $this->_NGINX_SRC_DIR, "modules"); +} + +sub test { + my $this=shift; + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' + tmp_conf=$(mktemp -p .) + for pre_dep in "$@"; do + echo "load_module modules/$pre_dep;" >> "$tmp_conf" + done + for i in *.so; do + echo "load_module $PWD/$i;" >> "$tmp_conf" + done + echo "events{}" >> "$tmp_conf" + nginx -g "error_log /dev/null; pid /dev/null;" -t -q -c "$PWD/$tmp_conf" + rm -f "$tmp_conf" + ', "dummy", @_); +} + +sub install { + my $this=shift; + my $destdir=shift; + + $this->doit_in_builddir("bash", "-e", "-o", "pipefail", "-c", ' + destdir=$1 + mkdir -p "$destdir/usr/lib/nginx/modules" + for i in *.so; do + cp "$i" "$destdir/usr/lib/nginx/modules/" + done + ', "dummy", $destdir); +} + +sub clean { + my $this=shift; + $this->rmdir_builddir(); +} + +1 diff --git a/debian/dh_nginx b/debian/dh_nginx index 8e6ce3b..4853568 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -48,7 +48,7 @@ sub nginx_modules_conf_installdir =head1 SYNOPSIS -B [S>] [B<-n>|B<--noscripts>] +B [S>] [B<-n>|B<--noscripts>] [B<--in-nginx-tree>] =head1 DESCRIPTION @@ -63,6 +63,8 @@ It supports the following configuration types =item * Nginx modules +=back + =head1 INVOCATION %: @@ -128,6 +130,10 @@ configuration by default. Do not modify F/F/F maintainer scripts. +=item B<--in-nginx-tree> + +Specify this option when building in-tree modules along with nginx. When +specified, nginx abi version is not required in package name. =back @@ -150,8 +156,11 @@ dh_nginx is heavily influnced by dh_apache2 written by Arno Toell ## main code starts here ## +my $nginx_in_tree; + init(options => { "e|noenable" => \$dh{NOENABLE}, + "in-nginx-tree" => \$nginx_in_tree, }); foreach my $package ((@{$dh{DOPACKAGES}})) @@ -231,7 +240,12 @@ foreach my $package ((@{$dh{DOPACKAGES}})) { warning("Package $package appears to be an Nginx module. It should comply to the package naming scheme libnginx-mod-\n"); } - addsubstvar($package, "misc:Depends", nginx_depends()); + if ($nginx_in_tree){ + addsubstvar($package, "misc:Depends", nginx_depends()); + } else { + my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + addsubstvar($package, "misc:Depends", "nginx-common (>= $ngx_ver), nginx-common (<< $ngx_ver.1~)"); + } my $modules = ""; foreach my $module (@{$PACKAGE_TYPE{'has_a_module'}}) diff --git a/debian/nginx-dev.install b/debian/nginx-dev.install new file mode 100644 index 0000000..6a2ad43 --- /dev/null +++ b/debian/nginx-dev.install @@ -0,0 +1,8 @@ +debian/build-src/auto usr/share/nginx/src/ +debian/build-src/src usr/share/nginx/src/ +debian/build-src/conf_flags usr/share/nginx/src/ +debian/build-src/configure usr/share/nginx/src/ +debian/debhelper/nginx.pm usr/share/perl5/Debian/Debhelper/Sequence/ +debian/dh_nginx usr/bin/ +debian/debhelper/nginx_mod.pm usr/share/perl5/Debian/Debhelper/Buildsystem/ +debian/autoscripts/* usr/share/debhelper/autoscripts/ diff --git a/debian/nginx-dev.manpages b/debian/nginx-dev.manpages new file mode 100644 index 0000000..0ece920 --- /dev/null +++ b/debian/nginx-dev.manpages @@ -0,0 +1 @@ +debian/build-src/dh_nginx.1 diff --git a/debian/rules b/debian/rules index f777843..68ed613 100755 --- a/debian/rules +++ b/debian/rules @@ -32,7 +32,7 @@ DYN_MODS := \ MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) -$(foreach flavour,$(FLAVOURS),$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) +$(foreach flavour,$(FLAVOURS) src,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) DEB_BUILD_ARCH ?=$(shell dpkg-architecture -qDEB_BUILD_ARCH) ifeq ($(DEB_BUILD_ARCH),sparc) @@ -48,9 +48,7 @@ MODULESPATCHDIR = $(CURDIR)/debian/modules/patches modules_with_patches := $(notdir $(wildcard $(CURDIR)/debian/modules/patches/*)) # configure flags -common_configure_flags := \ - --with-cc-opt="$(debian_cflags)" \ - --with-ld-opt="$(debian_ldflags)" \ +basic_configure_flags := \ --prefix=/usr/share/nginx \ --conf-path=/etc/nginx/nginx.conf \ --http-log-path=/var/log/nginx/access.log \ @@ -75,6 +73,11 @@ common_configure_flags := \ --with-http_slice_module \ --with-threads +common_configure_flags := \ + --with-cc-opt="$(debian_cflags)" \ + --with-ld-opt="$(debian_ldflags)" \ + $(basic_configure_flags) + light_configure_flags := \ $(common_configure_flags) \ --with-http_gzip_static_module \ @@ -132,15 +135,15 @@ extras_configure_flags := \ %: dh $@ --without autoreconf -override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) -override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) +override_dh_auto_configure: config_patch_modules $(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: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src dh_clean override_dh_install: dh_install - DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx --in-nginx-tree override_dh_installinit: dh_installinit --no-stop-on-upgrade --no-start --name=nginx @@ -154,6 +157,14 @@ override_dh_installlogrotate: build.arch.%: $(MAKE) -C $(BUILDDIR_$*) build +build.src: + cp -Pa $(CURDIR)/auto $(BUILDDIR_src)/ + sed -i '/^# create Makefile/,/^END$$/d' $(BUILDDIR_src)/auto/make $(BUILDDIR_src)/auto/init $(BUILDDIR_src)/auto/install + find $(CURDIR)/src -type f -name '*.h' -printf 'src/%P\0' | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_src)/ -x + if [ -e $(CURDIR)/configure ]; then cp $(CURDIR)/configure $(BUILDDIR_src)/; fi + echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags + pod2man debian/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 + strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' @@ -182,6 +193,10 @@ config.arch.%: cp -Pa $(CURDIR)/man $(BUILDDIR_$*)/ cd $(BUILDDIR_$*) && ./configure $($*_configure_flags) +config.src: + dh_testdir + mkdir -p $(BUILDDIR_src) + clean.%: rm -rf $(BUILDDIR_$*) From 87b5e38f6d10b13e7fd567c9e430153c48d7bafc Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Thu, 26 May 2022 15:48:54 +0800 Subject: [PATCH 209/414] nginx-dev: simplify dependencies nginx-dev depends on ${S:Build-Depends} before this commit, to include all the build-depdencies of nginx source packages. However, this also includes build dependency for those in-tree 3rd party modules, which are unnecessary. This commit removes them and explicitly list those packages needed to build a general module. The architecture of nginx-dev can thus be changed to all instead of any. When all 3rd party modules are removed, the dependency can be changed back to ${S:Build-Depends} to make the config less redundant. --- debian/control | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/debian/control b/debian/control index 9f31ba4..f6b11ba 100644 --- a/debian/control +++ b/debian/control @@ -69,9 +69,21 @@ Description: small, powerful, scalable web/proxy server - common files nginx. Package: nginx-dev -Architecture: any -Depends: ${misc:Depends}, ${S:Build-Depends}, - nginx-core (= ${binary:Version}) | nginx-light (= ${binary:Version}) | nginx-extras (= ${binary:Version}) +Architecture: all +Depends: ${misc:Depends}, + debhelper-compat (= 13), + dpkg-dev (>= 1.15.5), + libgd-dev, + libgeoip-dev, + libpcre3-dev, + libperl-dev, + libssl-dev, + libxslt1-dev, + po-debconf, + quilt, + zlib1g-dev, + nginx-core (<< ${source:Version}.1~) | nginx-light (<< ${source:Version}.1~) | nginx-extras (<< ${source:Version}.1~), + nginx-core (>= ${source:Version}) | nginx-light (>= ${source:Version}) | nginx-extras (>= ${source:Version}) Description: nginx web/proxy server - development headers Nginx ("engine X") is a high-performance web and reverse proxy server created by Igor Sysoev. It can be used both as a standalone web server From 2784d3f935d26fab5d485caa6843221f2691686b Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 27 May 2022 00:09:29 +0800 Subject: [PATCH 210/414] nginx-dev: fix nginx version subtracting in dh_nginx --- debian/dh_nginx | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/dh_nginx b/debian/dh_nginx index 4853568..e07ffe1 100755 --- a/debian/dh_nginx +++ b/debian/dh_nginx @@ -244,6 +244,7 @@ foreach my $package ((@{$dh{DOPACKAGES}})) addsubstvar($package, "misc:Depends", nginx_depends()); } else { my $ngx_ver = `grep 'define NGINX_VERSION' /usr/share/nginx/src/src/core/nginx.h | sed -e 's/^.*"\\(.*\\)".*/\\1/'`; + chomp($ngx_ver); addsubstvar($package, "misc:Depends", "nginx-common (>= $ngx_ver), nginx-common (<< $ngx_ver.1~)"); } From 15c55ec59b0f542e9cecf7205e5e54a0d6beba2e Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 6 May 2022 18:59:25 +0800 Subject: [PATCH 211/414] dh_nginx: move to debian/debhelper Move dh_nginx script to debian/debhelper so that all debhelper scripts are located together. --- debian/{ => debhelper}/dh_nginx | 0 debian/nginx-dev.install | 2 +- debian/rules | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) rename debian/{ => debhelper}/dh_nginx (100%) diff --git a/debian/dh_nginx b/debian/debhelper/dh_nginx similarity index 100% rename from debian/dh_nginx rename to debian/debhelper/dh_nginx diff --git a/debian/nginx-dev.install b/debian/nginx-dev.install index 6a2ad43..efc1578 100644 --- a/debian/nginx-dev.install +++ b/debian/nginx-dev.install @@ -3,6 +3,6 @@ debian/build-src/src usr/share/nginx/src/ debian/build-src/conf_flags usr/share/nginx/src/ debian/build-src/configure usr/share/nginx/src/ debian/debhelper/nginx.pm usr/share/perl5/Debian/Debhelper/Sequence/ -debian/dh_nginx usr/bin/ +debian/debhelper/dh_nginx usr/bin/ debian/debhelper/nginx_mod.pm usr/share/perl5/Debian/Debhelper/Buildsystem/ debian/autoscripts/* usr/share/debhelper/autoscripts/ diff --git a/debian/rules b/debian/rules index 68ed613..d4ddc7e 100755 --- a/debian/rules +++ b/debian/rules @@ -143,7 +143,7 @@ override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),cl override_dh_install: dh_install - DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/dh_nginx --in-nginx-tree + DH_AUTOSCRIPTDIR=$(CURDIR)/debian/autoscripts debian/debhelper/dh_nginx --in-nginx-tree override_dh_installinit: dh_installinit --no-stop-on-upgrade --no-start --name=nginx @@ -163,7 +163,7 @@ build.src: find $(CURDIR)/src -type f -name '*.h' -printf 'src/%P\0' | tar -C $(CURDIR) --null --files-from - -c | tar -C $(BUILDDIR_src)/ -x if [ -e $(CURDIR)/configure ]; then cp $(CURDIR)/configure $(BUILDDIR_src)/; fi echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags - pod2man debian/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 + 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~)' From 509adba304b06ff3fcb99b0baa8ef689e4bed40d Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Fri, 6 May 2022 19:09:50 +0800 Subject: [PATCH 212/414] dh_nginx: support auto generating module config files This patch adds support of auto generating module config files for modules in the naming pattern of libnginx-mod-* but with missing .nginx file. The module load file and its loading priority is inferred from the package name in this case. Using this feature, the repeated files d/libnginx-mod-*.nginx and d/libnginx-mod.conf/ can be removed, and the packaging for out-of-tree modules can be simplified. --- debian/debhelper/dh_nginx | 122 ++++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 43 deletions(-) diff --git a/debian/debhelper/dh_nginx b/debian/debhelper/dh_nginx index e07ffe1..f2b9bb5 100755 --- a/debian/debhelper/dh_nginx +++ b/debian/debhelper/dh_nginx @@ -84,6 +84,11 @@ Lists files to be registered with the Nginx HTTP server. The file is interpreted as line separated list of installation stanzas, where each entry consists of whitespace separated values conforming to the file semantics below. +When this file is missing but the name of the package looks like a nginx module, +the module load file and its loading priority is automatically generated inferring +from the package name. In this case, IB<.install> or other mechanisms +should be used for copying the B<.so> library into the correct place. + =head2 FILE SEMANTICS Each line consists of a triple @@ -171,65 +176,96 @@ foreach my $package ((@{$dh{DOPACKAGES}})) my $file = pkgfile($package, "nginx"); my $tmp = tmpdir($package); + my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); + my $modinstalldir = $tmp . "/" . nginx_api_installdir(); - my @files_to_register = filedoublearray($file, ".") if $file; - foreach my $line (@files_to_register) - { - my $type = lc(shift @{$line}) if $line->[0]; - my $source = shift @{$line} if $line->[0]; - my @arguments = @{$line}; - my $destination; - - $type = "modules" if $type eq "mod"; - my $installdir = $tmp . "/" . nginx_modules_conf_installdir(); - - verbose_print("$type -- $source -- @arguments\n\n"); - - if ($type eq "modules") + if ($file){ + my @files_to_register = filedoublearray($file, ".") if $file; + foreach my $line (@files_to_register) { - my $basesource = basename($source); + my $type = lc(shift @{$line}) if $line->[0]; + my $source = shift @{$line} if $line->[0]; + my @arguments = @{$line}; + my $destination; + + $type = "modules" if $type eq "mod"; + + verbose_print("$type -- $source -- @arguments\n\n"); if ($type eq "modules") { - if ($basesource =~ m/\.conf$/) + my $basesource = basename($source); + + if ($type eq "modules") { - my $enablename = $basesource; - my $prio = $#arguments >= 0 ? $arguments[0] : 50; - $destination = "$prio-$basesource"; - push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; - verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); - } - elsif ($basesource =~ m/\.so$/) - { - my $modinstalldir = $tmp . "/" . nginx_api_installdir(); - verbose_print("Installing module binary $source into $modinstalldir\n"); - if (! -d $modinstalldir) + if ($basesource =~ m/\.conf$/) { - complex_doit("mkdir","-p", $modinstalldir); - complex_doit("chmod","755","$modinstalldir"); + my $enablename = $basesource; + my $prio = $#arguments >= 0 ? $arguments[0] : 50; + $destination = "$prio-$basesource"; + push @{$PACKAGE_TYPE{'has_a_module'}}, "$enablename:$destination"; + verbose_print("Installing module configuration $enablename into $installdir prio:$prio\n"); } - complex_doit("cp", $source, $modinstalldir); - next; + elsif ($basesource =~ m/\.so$/) + { + verbose_print("Installing module binary $source into $modinstalldir\n"); + if (! -d $modinstalldir) + { + complex_doit("mkdir","-p", $modinstalldir); + complex_doit("chmod","755","$modinstalldir"); + } + complex_doit("cp", $source, $modinstalldir); + next; + } + + # TODO + error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; } - # TODO - error("module: \"$basesource\" needs .conf, .so or suffix") if $basesource !~ m/\.(conf|so)/; - } + if (! -d $installdir) + { + complex_doit("mkdir","-p",$installdir); + complex_doit("chmod","755","$installdir"); + } + complex_doit("cp",$source,$installdir); + complex_doit("chmod","644","$installdir/$basesource"); - if (! -d $installdir) + } + else { - complex_doit("mkdir","-p",$installdir); - complex_doit("chmod","755","$installdir"); + error("Unknown parameter: $type\n"); } - complex_doit("cp",$source,$installdir); - complex_doit("chmod","644","$installdir/$basesource"); } - else - { - error("Unknown parameter: $type\n"); - } + } elsif ($package =~ /^libnginx-mod-/){ + verbose_print("$package might be a nginx module\n"); + my $module = $package; + $module =~ s/^libnginx-mod-//; + verbose_print("Guessed module name: $module\n"); + + my $modulepath = $module; + $modulepath =~ s/-/_/g; + + if (-e "$modinstalldir/ngx_${modulepath}_module.so"){ + my $prio = 50; + if ($module =~ /^\w+-/ && !($module =~ /^http-/) ){ + $prio = 70; + } + verbose_print("Guessed load priority: $prio\n"); + + my $conf_name = "mod-$module.conf"; + install_dir($installdir); + verbose_print("Installing module configuration $conf_name into $installdir prio:$prio\n"); + open(MOD_CONF, $dh{NO_ACT} ? ">&STDERR" : ">$installdir/$conf_name") or error("open($installdir/$conf_name): $!"); + print(MOD_CONF "load_module modules/ngx_${modulepath}_module.so;\n"); + close(MOD_CONF); + chmod(0644, "$installdir/$conf_name") or error("chmod(0644, $installdir/$conf_name): $!"); + push @{$PACKAGE_TYPE{'has_a_module'}}, "$conf_name:$prio-$conf_name"; + } else { + verbose_print("$package is not a nginx module because $modinstalldir/ngx_${modulepath}_module.so not found"); + verbose_print("If it is not correct, check if the module is installed before invoking this script"); + } } my @postinst_autoscripts; From ed5bc15213993766af66189792d5a7ed496681e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 15 May 2022 09:12:16 +0200 Subject: [PATCH 213/414] Remove 0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch --- ...ure-stays-the-same-in-all-nginx-buil.patch | 28 ------------------- debian/patches/series | 1 - 2 files changed, 29 deletions(-) delete mode 100644 debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch diff --git a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch b/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch deleted file mode 100644 index 9e27e1a..0000000 --- a/debian/patches/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch +++ /dev/null @@ -1,28 +0,0 @@ -From: Christos Trochalakis -Date: Wed, 30 Mar 2016 09:47:11 +0300 -Subject: Make sure signature stays the same in all nginx builds - -NGX_HTTP_HEADERS is part of nginx signature. When a dyn -modules is loaded the signature of the module is compared -to the one of the nginx binary. - -dyn modules are build from nginx-full, so in order to make -them loadable in other flavors we need to make sure all the -binaries share the same signature. ---- - configure | 4 ++++ - 1 file changed, 4 insertions(+) - ---- a/configure -+++ b/configure -@@ -58,6 +58,10 @@ - . auto/unix - fi - -+# Debian -+# Make sure signature stays the same on all nginx flavors -+have=NGX_HTTP_HEADERS . auto/have -+ - . auto/threads - . auto/modules - . auto/lib/conf diff --git a/debian/patches/series b/debian/patches/series index 5b6b799..04030f9 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ -0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch 0003-define_gnu_source-on-other-glibc-based-platforms.patch From 9f1044b9401f8b40ebefa306761ecd9a951750ba Mon Sep 17 00:00:00 2001 From: Miao Wang Date: Sun, 26 Jun 2022 15:26:40 +0800 Subject: [PATCH 214/414] changelog: update changelog --- debian/changelog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index fec8e1d..581bd2e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,14 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + [ Miao Wang ] + * dh_nginx: support auto generating module config files + * adding a new nginx-dev package including necessary headers and debhelper + scripts to build and package a 3rd party module. + * d/p/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch + removed, because feature already implemented with --with-compat configure + option since 1.11.5 + -- Thomas Ward Tue, 10 May 2022 12:08:02 -0400 nginx (1.20.2-2) unstable; urgency=medium From 83ca2994f8be7c48e6cfe82236d5268bc3e29f93 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Tue, 17 May 2022 15:42:18 -0400 Subject: [PATCH 215/414] Copyright file needed updated (caught by Bage, who emailed a patch to teward) --- debian/changelog | 3 +++ debian/copyright | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/debian/changelog b/debian/changelog index 581bd2e..542e5a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -28,6 +28,9 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + [ Bastian Germann ] + * d/copyright: Update copyright for d/debhelper/* + [ Miao Wang ] * dh_nginx: support auto generating module config files * adding a new nginx-dev package including necessary headers and debhelper diff --git a/debian/copyright b/debian/copyright index 59dfc09..6449e69 100644 --- a/debian/copyright +++ b/debian/copyright @@ -47,6 +47,10 @@ Copyright: 2007-2009, Fabio Tranchitella 2020-2022, Ondřej Nový License: BSD-2-clause +Files: debian/debhelper/* +Copyright: 2022 Miao Wang +License: Expat + Files: debian/modules/http-headers-more-filter/* Copyright: 2009-2017, Yichun "agentzh" Zhang (章亦春) , CloudFlare Inc. 2010-2013, Bernd Dorn From bf9c433dbbb5d6accb5546a805dacf59e04f5d99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 14:35:33 +0200 Subject: [PATCH 216/414] d/control: bump Standards-Version to 4.6.1, no changes --- debian/changelog | 1 + debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 542e5a6..fe5fc20 100644 --- a/debian/changelog +++ b/debian/changelog @@ -27,6 +27,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium * d/copyright: bump nginx copyright years * d/copyright: added copyright for src/stream/ngx_stream_set_module.c * d/copyright: removed copyright for src/http/v2/ngx_http_v2_huff_encode.c + * d/control: bump Standards-Version to 4.6.1, no changes [ Bastian Germann ] * d/copyright: Update copyright for d/debhelper/* diff --git a/debian/control b/debian/control index f6b11ba..21eb530 100644 --- a/debian/control +++ b/debian/control @@ -24,7 +24,7 @@ Build-Depends: debhelper-compat (= 13), po-debconf, quilt, zlib1g-dev -Standards-Version: 4.6.0 +Standards-Version: 4.6.1 Homepage: https://nginx.org Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git Vcs-Browser: https://salsa.debian.org/nginx-team/nginx From 7df2636a9d22b2fb385f06af25a61f929b9b4bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:16:08 +0200 Subject: [PATCH 217/414] d/changelog fix whitespace --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index fe5fc20..68a4ac4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,7 +11,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium was added to the keyring while keeping Maxim's key in signing keys as well. * d/copyright: Updated copyright for src/core/ngx_murmurhash.c - and debian/modules/http-ndk/src/hash/murmurhash2.c to be + and debian/modules/http-ndk/src/hash/murmurhash2.c to be public-domain (Closes: #1011936) * d/control: Use libluajit-5.1-dev for s390x. Due to src:luajit2 landing in Unstable, superseding src:luajit, From 172eb7b12a8ba0bf4667e54835b5d2024adadc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:16:58 +0200 Subject: [PATCH 218/414] d/changelog close #1013807 bug --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 68a4ac4..a12536e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,7 +19,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium with luajit instead of standard Lua. Thanks to Paul Gevers for the heads up on luajit2 supporting s390x. * d/control: Use liblua for ppc64el - src:luajit2 is still not ppc64el - stable and there seems to be nobody willing to support it. + stable and there seems to be nobody willing to support it. (Closes: 1013807) [ Jan Mojžíš ] * d/patches/CVE-2021-3618.patch removed, fix is included in new upstream From 42508c8556723f6e499bba2850f13a97665374fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:20:26 +0200 Subject: [PATCH 219/414] create var/www/html in nginx-common.postinst --- debian/nginx-common.dirs | 1 - debian/nginx-common.lintian-overrides | 2 -- debian/nginx-common.postinst | 1 + 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 debian/nginx-common.lintian-overrides diff --git a/debian/nginx-common.dirs b/debian/nginx-common.dirs index 65bb651..8e5d7bf 100644 --- a/debian/nginx-common.dirs +++ b/debian/nginx-common.dirs @@ -10,4 +10,3 @@ usr/share/vim/addons usr/share/vim/registry var/lib/nginx var/log/nginx -var/www/html diff --git a/debian/nginx-common.lintian-overrides b/debian/nginx-common.lintian-overrides deleted file mode 100644 index 35cc9bc..0000000 --- a/debian/nginx-common.lintian-overrides +++ /dev/null @@ -1,2 +0,0 @@ -# /var/www/html is the default document root -nginx-common: dir-or-file-in-var-www var/www/html/ diff --git a/debian/nginx-common.postinst b/debian/nginx-common.postinst index 9e0610e..0d44608 100644 --- a/debian/nginx-common.postinst +++ b/debian/nginx-common.postinst @@ -39,6 +39,7 @@ case "$1" in # Create a default index page when not already present. if [ ! -e /var/www/html/index.nginx-debian.html ]; then + mkdir -p /var/www/html cp /usr/share/nginx/html/index.html /var/www/html/index.nginx-debian.html fi From 1a3b0014140ee9b085732cf31457435d70f9a713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 26 Jun 2022 16:41:06 +0200 Subject: [PATCH 220/414] d/changelog close #985133 bug --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index a12536e..1409f33 100644 --- a/debian/changelog +++ b/debian/changelog @@ -35,7 +35,7 @@ nginx (1.22.0-1) UNRELEASED; urgency=medium [ Miao Wang ] * dh_nginx: support auto generating module config files * adding a new nginx-dev package including necessary headers and debhelper - scripts to build and package a 3rd party module. + scripts to build and package a 3rd party module. (Closes: 985133) * d/p/0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch removed, because feature already implemented with --with-compat configure option since 1.11.5 From 035ed7f34a7c35aee9e008eb26f5a5c99f15ca82 Mon Sep 17 00:00:00 2001 From: Thomas Ward Date: Sat, 9 Jul 2022 20:14:24 -0400 Subject: [PATCH 221/414] Unstable upload --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 1409f33..46c9e92 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.0-1) UNRELEASED; urgency=medium +nginx (1.22.0-1) unstable; urgency=medium [ Thomas Ward ] * New upstream release (1.22.0) From ccd67189200544340c52c67bebd8eeea797a5b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 08:21:23 +0200 Subject: [PATCH 222/414] d/nginx-common.nginx.service update --- debian/changelog | 12 ++++++++++++ debian/nginx-common.nginx.service | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 46c9e92..609ac41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,15 @@ +nginx (1.22.0-2) UNRELEASED; urgency=medium + + * d/nginx-common.nginx.service: added Systemd dependency + Wants=network-online.target and updated Systemd "After" dependency to + recommended NGINX values, namely: + - syslog.target + - network-online.target (Closes: 61261) (Closes: 1000406) + - remote-fs.target (Closes: 898896) + - nss-lookup.target + + -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 + nginx (1.22.0-1) unstable; urgency=medium [ Thomas Ward ] diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index 78bf0ce..a46a725 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -13,7 +13,8 @@ [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) -After=network.target nss-lookup.target +After=syslog.target network-online.target remote-fs.target nss-lookup.target +Wants=network-online.target [Service] Type=forking From 88d4d1577a0387abc4cf2d6b039711bfd7c142af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 08:29:08 +0200 Subject: [PATCH 223/414] d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch forwarded to upstream --- debian/changelog | 2 ++ .../0003-define_gnu_source-on-other-glibc-based-platforms.patch | 1 + 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 609ac41..749ec29 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,8 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium - network-online.target (Closes: 61261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target + * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded + to upstream (Closes: 859082) -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch index d43fd23..caf155f 100644 --- a/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch +++ b/debian/patches/0003-define_gnu_source-on-other-glibc-based-platforms.patch @@ -1,6 +1,7 @@ Date: Sat, 16 Jul 2016 23:52:50 +0100 From: Steven Chamberlain Subject: Use _GNU_SOURCE on GNU/kFreeBSD +Forwarded: https://trac.nginx.org/nginx/ticket/2366 Define _GNU_SOURCE not only on GNU/Hurd, but also other glibc-based platforms including GNU/kFreeBSD. From ff7cd7012d526745b8b5bc514877e2be0a487da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 18:32:08 +0200 Subject: [PATCH 224/414] d/t/reboot: added, tests if nginx works after reboot --- debian/changelog | 1 + debian/tests/control | 4 ++++ debian/tests/reboot | 15 +++++++++++++++ 3 files changed, 20 insertions(+) create mode 100644 debian/tests/reboot diff --git a/debian/changelog b/debian/changelog index 749ec29..adf2e41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium - nss-lookup.target * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded to upstream (Closes: 859082) + * d/t/reboot: added, tests if nginx works after reboot -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/tests/control b/debian/tests/control index 52690ae..4a24735 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -125,3 +125,7 @@ Depends: nginx-extras, libnginx-mod-stream-geoip, libnginx-mod-stream-geoip2, libnginx-mod-stream, + +Tests: reboot +Restrictions: isolation-container, needs-root, needs-reboot +Depends: nginx-light, curl diff --git a/debian/tests/reboot b/debian/tests/reboot new file mode 100644 index 0000000..a90a6c9 --- /dev/null +++ b/debian/tests/reboot @@ -0,0 +1,15 @@ +#!/bin/sh +# 20220710 +# Jan Mojzis +# Public domain + +#change directory to $AUTOPKGTEST_TMP +cd "${AUTOPKGTEST_TMP}" + +# do simple curl +curl --silent --fail -o /dev/null -w "response_code: %{http_code}\n" http://127.0.0.1/ + +# test if nginx runs after reboot +if [ x"${AUTOPKGTEST_REBOOT_MARK}" = x ]; then + /tmp/autopkgtest-reboot rebootmark +fi From 461acc4f5141c73b01531283c035580608073e97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sun, 10 Jul 2022 20:12:32 +0200 Subject: [PATCH 225/414] d/nginx-common.nginx.service: remove systemd 'After' dependency syslog.target, is obsolete --- debian/changelog | 1 - debian/nginx-common.nginx.service | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index adf2e41..d9adaf3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,6 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: - - syslog.target - network-online.target (Closes: 61261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target diff --git a/debian/nginx-common.nginx.service b/debian/nginx-common.nginx.service index a46a725..a63fa0f 100644 --- a/debian/nginx-common.nginx.service +++ b/debian/nginx-common.nginx.service @@ -13,7 +13,7 @@ [Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) -After=syslog.target network-online.target remote-fs.target nss-lookup.target +After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target [Service] From 0d813834ef16b455986c8aea98f9f0a1158eff02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 11 Jul 2022 20:33:33 +0200 Subject: [PATCH 226/414] http-subs-filter add PCRE2 support --- debian/changelog | 1 + .../patches/http-subs-filter/pcre2.patch | 24 +++++++++++++++++++ .../modules/patches/http-subs-filter/series | 1 + 3 files changed, 26 insertions(+) create mode 100644 debian/modules/patches/http-subs-filter/pcre2.patch diff --git a/debian/changelog b/debian/changelog index d9adaf3..9fb216f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded to upstream (Closes: 859082) * d/t/reboot: added, tests if nginx works after reboot + * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 diff --git a/debian/modules/patches/http-subs-filter/pcre2.patch b/debian/modules/patches/http-subs-filter/pcre2.patch new file mode 100644 index 0000000..692257c --- /dev/null +++ b/debian/modules/patches/http-subs-filter/pcre2.patch @@ -0,0 +1,24 @@ +Author: shmux8 <75251845+shmux8@users.noreply.github.com> +Date: Tue Dec 28 11:15:00 2021 +0300 +Subject: [PATCH] pcre2 support +Origin: https://github.com/yaoweibin/ngx_http_substitutions_filter_module/commit/cc494d7f5c5273a7a8ae503faebf1101689d75c0 + + PCRE2 support added + + Use pcre2_pattern_info call if nginx built with PCRE2. + +diff --git a/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c b/debian/modules/http-subs-filter/ngx_http_subs_filter_module.c +index 483c9c3..11a5b79 100644 +--- a/ngx_http_subs_filter_module.c ++++ b/ngx_http_subs_filter_module.c +@@ -1203,7 +1203,9 @@ ngx_http_subs_regex_capture_count(ngx_regex_t *re) + + n = 0; + +-#if defined(nginx_version) && nginx_version >= 1002002 ++#if (NGX_PCRE2) ++ rc = pcre2_pattern_info(re, PCRE2_INFO_CAPTURECOUNT, &n); ++#elif defined(nginx_version) && nginx_version >= 1002002 + rc = pcre_fullinfo(re->code, NULL, PCRE_INFO_CAPTURECOUNT, &n); + #elif defined(nginx_version) && nginx_version >= 1001012 + rc = pcre_fullinfo(re->pcre, NULL, PCRE_INFO_CAPTURECOUNT, &n); diff --git a/debian/modules/patches/http-subs-filter/series b/debian/modules/patches/http-subs-filter/series index f9b9360..4344c0b 100644 --- a/debian/modules/patches/http-subs-filter/series +++ b/debian/modules/patches/http-subs-filter/series @@ -1 +1,2 @@ dynamic-module.patch +pcre2.patch From 0e2eaec4b255c46654b049f593a03368083d7b48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:40:40 +0200 Subject: [PATCH 227/414] d/gitlab-ci.yml removed in GL switched to salsa-ci team recipes/debian.yml@salsa-ci-team/pipeline --- debian/gitlab-ci.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml deleted file mode 100644 index 557434c..0000000 --- a/debian/gitlab-ci.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml - -# Disable reprotest which is failing now -variables: - SALSA_CI_DISABLE_REPROTEST: 1 From 142c95ade023fd91eed22a5c1b7c2525b79b13d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:46:55 +0200 Subject: [PATCH 228/414] add libnginx-mod-http-ndk-dev to nginx to build ngx-lua --- debian/changelog | 5 +++++ debian/control | 16 +++++++++++++++ debian/libnginx-mod-http-ndk-dev.install | 5 +++++ debian/rules | 26 ++++++++++++++++++++---- 4 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 debian/libnginx-mod-http-ndk-dev.install diff --git a/debian/changelog b/debian/changelog index 9fb216f..194e492 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,10 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium + [ Miao Wang ] + * adding a new libnginx-mod-http-ndk-dev package including necessary + headers to build a 3rd party module depending on ndk. + + [ Jan Mojžíš ] * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: diff --git a/debian/control b/debian/control index 21eb530..4736a9f 100644 --- a/debian/control +++ b/debian/control @@ -398,6 +398,22 @@ Description: Nginx Development Kit module 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 +Depends: libnginx-mod-http-ndk (<< ${source:Version}.1~), libnginx-mod-http-ndk (>= ${source:Version}), + nginx-dev (>= ${source:Version}), nginx-dev (<< ${source:Version}.1~), ${misc: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. + Package: libnginx-mod-nchan Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/libnginx-mod-http-ndk-dev.install b/debian/libnginx-mod-http-ndk-dev.install new file mode 100644 index 0000000..980066f --- /dev/null +++ b/debian/libnginx-mod-http-ndk-dev.install @@ -0,0 +1,5 @@ +debian/build-ndksrc/auto usr/share/nginx-ndk/src/ +debian/build-ndksrc/src usr/share/nginx-ndk/src/ +debian/build-ndksrc/objs usr/share/nginx-ndk/src/ +debian/build-ndksrc/config usr/share/nginx-ndk/src/ +debian/build-ndksrc/ngx_auto_lib_core usr/share/nginx-ndk/src/ \ No newline at end of file diff --git a/debian/rules b/debian/rules index d4ddc7e..4471089 100755 --- a/debian/rules +++ b/debian/rules @@ -32,7 +32,7 @@ DYN_MODS := \ MODULESDIR = $(CURDIR)/debian/modules BASEDIR = $(CURDIR) -$(foreach flavour,$(FLAVOURS) src,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) +$(foreach flavour,$(FLAVOURS) src ndksrc,$(eval BUILDDIR_$(flavour) = $(CURDIR)/debian/build-$(flavour))) DEB_BUILD_ARCH ?=$(shell dpkg-architecture -qDEB_BUILD_ARCH) ifeq ($(DEB_BUILD_ARCH),sparc) @@ -135,10 +135,10 @@ extras_configure_flags := \ %: dh $@ --without autoreconf -override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src -override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src +override_dh_auto_configure: config_patch_modules $(foreach flavour,$(FLAVOURS),config.arch.$(flavour)) config.src config.ndksrc +override_dh_auto_build: $(foreach flavour,$(FLAVOURS),build.arch.$(flavour)) build.src build.ndksrc override_dh_strip: $(foreach flavour,$(FLAVOURS),strip.arch.$(flavour)) $(foreach mod,$(DYN_MODS),strip.mods.$(mod)) -override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src +override_dh_clean: clean_patch_modules $(foreach flavour,$(FLAVOURS),clean.$(flavour)) clean.src clean.ndksrc dh_clean override_dh_install: @@ -165,6 +165,16 @@ build.src: echo "NGX_CONF_FLAGS=(" $(basic_configure_flags) ")" > $(BUILDDIR_src)/conf_flags pod2man debian/debhelper/dh_nginx > $(BUILDDIR_src)/dh_nginx.1 +build.ndksrc: + cp -Pa $(CURDIR)/debian/modules/http-ndk/auto \ + $(CURDIR)/debian/modules/http-ndk/config \ + $(CURDIR)/debian/modules/http-ndk/ngx_auto_lib_core $(BUILDDIR_ndksrc)/ + for i in src objs; do \ + find $(CURDIR)/debian/modules/http-ndk/$$i -type f -name '*.h' -printf "$$i/%P\0" | \ + tar -C $(CURDIR)/debian/modules/http-ndk --null --files-from - -c | tar -C $(BUILDDIR_ndksrc)/ -x; \ + done + chmod +x $(CURDIR)/debian/build-ndksrc/auto/build + strip.arch.%: dh_strip --package=nginx-$(*) -O--dbgsym-migration='nginx-$(*)-dbg (<< 1.10.1-3~)' @@ -192,11 +202,19 @@ config.arch.%: cp -Pa $(CURDIR)/src $(BUILDDIR_$*)/ cp -Pa $(CURDIR)/man $(BUILDDIR_$*)/ cd $(BUILDDIR_$*) && ./configure $($*_configure_flags) + if [ "$(BUILDDIR_$*)" = "$(BUILDDIR_extras)" ]; then \ + have="NDK_SET_VAR"; \ + /bin/echo -e "#ifndef $$have\n#define $$have 1\n#endif" >> $(BUILDDIR_$*)/objs/ngx_auto_config.h; \ + fi config.src: dh_testdir mkdir -p $(BUILDDIR_src) +config.ndksrc: + dh_testdir + mkdir -p $(BUILDDIR_ndksrc) + clean.%: rm -rf $(BUILDDIR_$*) From 43b9a879c9a5b7573336e339a0b43113e45a56ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:48:06 +0200 Subject: [PATCH 229/414] Remove constraints unnecessary since buster * Build-Depends: Drop versioned constraint on dpkg-dev. * nginx-common: Drop versioned constraint on lsb-base in Depends. * nginx-core: Drop versioned constraint on nginx in Breaks. * nginx-full: Drop versioned constraint on nginx in Breaks. * nginx-light: Drop versioned constraint on nginx in Breaks. * nginx-extras: Drop versioned constraint on nginx in Breaks. * libnginx-mod-http-perl: Drop versioned constraint on nginx-extras in Replaces. * Remove 5 maintscript entries from 1 files. --- debian/changelog | 12 ++++++++++++ debian/control | 10 ++-------- debian/nginx-common.maintscript | 8 -------- 3 files changed, 14 insertions(+), 16 deletions(-) delete mode 100644 debian/nginx-common.maintscript diff --git a/debian/changelog b/debian/changelog index 194e492..c0cbcdb 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,18 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/t/reboot: added, tests if nginx works after reboot * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support + [ Debian Janitor ] + * Remove constraints unnecessary since buster: + + Build-Depends: Drop versioned constraint on dpkg-dev. + + nginx-common: Drop versioned constraint on lsb-base in Depends. + + nginx-core: Drop versioned constraint on nginx in Breaks. + + nginx-full: Drop versioned constraint on nginx in Breaks. + + nginx-light: Drop versioned constraint on nginx in Breaks. + + nginx-extras: Drop versioned constraint on nginx in Breaks. + + libnginx-mod-http-perl: Drop versioned constraint on nginx-extras in + Replaces. + + Remove 5 maintscript entries from 1 files. + -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 nginx (1.22.0-1) unstable; urgency=medium diff --git a/debian/control b/debian/control index 4736a9f..c8aa03c 100644 --- a/debian/control +++ b/debian/control @@ -7,7 +7,6 @@ Uploaders: Christos Trochalakis , Thomas Ward , Jan Mojžíš , Build-Depends: debhelper-compat (= 13), - dpkg-dev (>= 1.15.5), libexpat-dev, libgd-dev, libgeoip-dev, @@ -58,7 +57,7 @@ Description: small, powerful, scalable web/proxy server - documentation Package: nginx-common Architecture: all Multi-Arch: foreign -Depends: lsb-base (>= 3.0-6), ${misc:Depends} +Depends: lsb-base, ${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 @@ -105,8 +104,7 @@ Depends: libnginx-mod-http-geoip (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1), - nginx-full (<< 1.18.0-1), +Breaks: nginx-full (<< 1.18.0-1), Replaces: nginx-full (<< 1.18.0-1), Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-light @@ -146,7 +144,6 @@ Depends: libnginx-mod-http-auth-pam, nginx-core (<< ${source:Version}.1~), ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Suggests: nginx-doc (= ${source:Version}) Description: nginx web/proxy server (standard version with 3rd parties) @@ -181,7 +178,6 @@ Depends: libnginx-mod-http-echo (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-extras, nginx-core Suggests: nginx-doc (= ${source:Version}) @@ -228,7 +224,6 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), iproute2, ${misc:Depends}, ${shlibs:Depends} -Breaks: nginx (<< 1.4.5-1) Provides: httpd, httpd-cgi, nginx Conflicts: nginx-core, nginx-light Suggests: nginx-doc (= ${source:Version}) @@ -351,7 +346,6 @@ Package: libnginx-mod-http-perl Architecture: any Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends}, Recommends: nginx, -Replaces: nginx-extras (<< 1.9.14-1) Description: Perl module for Nginx Embed Perl runtime into nginx. . diff --git a/debian/nginx-common.maintscript b/debian/nginx-common.maintscript deleted file mode 100644 index e1e7f53..0000000 --- a/debian/nginx-common.maintscript +++ /dev/null @@ -1,8 +0,0 @@ -# Handle naxsi removal -rm_conffile /etc/nginx/naxsi.rules 1.6.2-2~ -rm_conffile /etc/nginx/naxsi_core.rules 1.6.2-2~ -rm_conffile /etc/nginx/naxsi-ui.conf.1.4.1 1.6.2-2~ -rm_conffile /etc/nginx/naxsi-ui.conf 1.6.2-2~ - -# Handle upstart removal -rm_conffile /etc/init/nginx.conf 1.13.5-1~ From 861f1be8692fccce5996e26ee7f210c927ea6ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:49:48 +0200 Subject: [PATCH 230/414] d/p/nginx-fix-pidfile.patch backport from Ubuntu --- debian/changelog | 2 + debian/patches/nginx-fix-pidfile.patch | 89 ++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 92 insertions(+) create mode 100644 debian/patches/nginx-fix-pidfile.patch diff --git a/debian/changelog b/debian/changelog index c0cbcdb..7d70e35 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,8 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium to upstream (Closes: 859082) * d/t/reboot: added, tests if nginx works after reboot * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support + * d/p/nginx-fix-pidfile.patch: Fix NGINX PIDfile handling to avoid + SystemD race condition, this fix is backported from Ubuntu (Closes: 876365) [ Debian Janitor ] * Remove constraints unnecessary since buster: diff --git a/debian/patches/nginx-fix-pidfile.patch b/debian/patches/nginx-fix-pidfile.patch new file mode 100644 index 0000000..47a16ff --- /dev/null +++ b/debian/patches/nginx-fix-pidfile.patch @@ -0,0 +1,89 @@ +Description: Fix NGINX pidfile handling +Author: Tj +Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/nginx/+bug/1581864 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876365 +Last-Update: 2020-06-24 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +diff --git a/src/core/nginx.c b/src/core/nginx.c +index 9fcb0eb2..083eba1d 100644 +--- a/src/core/nginx.c ++++ b/src/core/nginx.c +@@ -338,14 +338,21 @@ main(int argc, char *const *argv) + ngx_process = NGX_PROCESS_MASTER; + } + ++ /* tell-tale to detect if this is parent or child process */ ++ ngx_int_t child_pid = NGX_BUSY; ++ + #if !(NGX_WIN32) + + if (ngx_init_signals(cycle->log) != NGX_OK) { + return 1; + } + ++ /* tell-tale that this code has been executed */ ++ child_pid--; ++ + if (!ngx_inherited && ccf->daemon) { +- if (ngx_daemon(cycle->log) != NGX_OK) { ++ child_pid = ngx_daemon(cycle->log); ++ if (child_pid == NGX_ERROR) { + return 1; + } + +@@ -358,8 +365,19 @@ main(int argc, char *const *argv) + + #endif + +- if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { +- return 1; ++ /* If ngx_daemon() returned the child's PID in the parent process ++ * after the fork() set ngx_pid to the child_pid, which gets ++ * written to the PID file, then exit. ++ * For NGX_WIN32 always write the PID file ++ * For others, only write it from the parent process */ ++ if (child_pid < NGX_OK || child_pid > NGX_OK) { ++ ngx_pid = child_pid > NGX_OK ? child_pid : ngx_pid; ++ if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { ++ return 1; ++ } ++ } ++ if (child_pid > NGX_OK) { ++ exit(0); + } + + if (ngx_log_redirect_stderr(cycle) != NGX_OK) { +diff --git a/src/os/unix/ngx_daemon.c b/src/os/unix/ngx_daemon.c +index 385c49b6..3719854c 100644 +--- a/src/os/unix/ngx_daemon.c ++++ b/src/os/unix/ngx_daemon.c +@@ -7,14 +7,17 @@ + + #include + #include ++#include + + + ngx_int_t + ngx_daemon(ngx_log_t *log) + { + int fd; ++ /* retain the return value for passing back to caller */ ++ pid_t pid_child = fork(); + +- switch (fork()) { ++ switch (pid_child) { + case -1: + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed"); + return NGX_ERROR; +@@ -23,7 +26,8 @@ ngx_daemon(ngx_log_t *log) + break; + + default: +- exit(0); ++ /* let caller do the exit() */ ++ return pid_child; + } + + ngx_parent = ngx_pid; diff --git a/debian/patches/series b/debian/patches/series index 04030f9..5e15dcc 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1 +1,2 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch +nginx-fix-pidfile.patch From c9a408aa6f2309b43efaa2b04c5cf788aa546fa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:50:45 +0200 Subject: [PATCH 231/414] d/apport/source_nginx.py: Add apport hooks for additional bug information gathering, the script is backported from Ubuntu --- debian/apport/source_nginx.py | 19 +++++++++++++++++++ debian/changelog | 3 +++ debian/nginx-common.install | 1 + 3 files changed, 23 insertions(+) create mode 100644 debian/apport/source_nginx.py diff --git a/debian/apport/source_nginx.py b/debian/apport/source_nginx.py new file mode 100644 index 0000000..aec6e8e --- /dev/null +++ b/debian/apport/source_nginx.py @@ -0,0 +1,19 @@ +''' +apport package hook for nginx packages + +Copyright (c) 2015, Thomas Ward +''' + +import apport.hookutils +import os +import subprocess + +def add_info(report, ui): + if (report['Package'].split()[0] != 'nginx-common' + and report['ProblemType'] == 'Package' + and os.path.isdir('/run/systemd/system')): + report['Journalctl_Nginx.txt'] = apport.hookutils.command_output( + ['journalctl', '-xe', '--unit=nginx.service']) + report['SystemctlStatusFull_Nginx.txt'] = subprocess.Popen( + ['systemctl', '-l', 'status', 'nginx.service'], + stdout=subprocess.PIPE).communicate()[0] diff --git a/debian/changelog b/debian/changelog index 7d70e35..0124d12 100644 --- a/debian/changelog +++ b/debian/changelog @@ -17,6 +17,9 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium * d/m/p/http-subs-filter/pcre2.patch: added PCRE2 support * d/p/nginx-fix-pidfile.patch: Fix NGINX PIDfile handling to avoid SystemD race condition, this fix is backported from Ubuntu (Closes: 876365) + * d/apport/source_nginx.py: Add apport hooks for additional bug + information gathering, the script is backported from Ubuntu (Closes: 963668) + * d/nginx-common.install: Add install rule for apport hooks. [ Debian Janitor ] * Remove constraints unnecessary since buster: diff --git a/debian/nginx-common.install b/debian/nginx-common.install index 90f173b..20109fa 100644 --- a/debian/nginx-common.install +++ b/debian/nginx-common.install @@ -1,5 +1,6 @@ contrib/vim/* usr/share/vim/addons debian/conf/* etc/nginx +debian/apport/source_nginx.py usr/share/apport/package-hooks debian/ufw/nginx etc/ufw/applications.d debian/vim/nginx.yaml usr/share/vim/registry html/index.html usr/share/nginx/html/ From 13a5fc3501349113ac90636d8f47d007ffafd033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Sat, 23 Jul 2022 10:40:40 +0200 Subject: [PATCH 232/414] d/gitlab-ci.yml removed in GL switched to salsa-ci team recipes/debian.yml@salsa-ci-team/pipeline --- debian/gitlab-ci.yml | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 debian/gitlab-ci.yml diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml deleted file mode 100644 index 557434c..0000000 --- a/debian/gitlab-ci.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml - -# Disable reprotest which is failing now -variables: - SALSA_CI_DISABLE_REPROTEST: 1 From 08de4d4bc7e6ba11051ab1f6ef5460989b161513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Lal?= Date: Sun, 7 Aug 2022 16:15:09 +0200 Subject: [PATCH 233/414] Release to unstable --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 0124d12..6bb8afa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -nginx (1.22.0-2) UNRELEASED; urgency=medium +nginx (1.22.0-2) unstable; urgency=medium [ Miao Wang ] * adding a new libnginx-mod-http-ndk-dev package including necessary @@ -33,7 +33,7 @@ nginx (1.22.0-2) UNRELEASED; urgency=medium Replaces. + Remove 5 maintscript entries from 1 files. - -- Jan Mojžíš Sun, 10 Jul 2022 07:58:44 +0200 + -- Jan Mojžíš Sun, 07 Aug 2022 16:14:59 +0200 nginx (1.22.0-1) unstable; urgency=medium From a316cb99e4dcc4ba7306b4741f474500784c270f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:30:21 +0200 Subject: [PATCH 234/414] d/changelog: fix typo in bug number 61261 -> 861261 --- debian/changelog | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 6bb8afa..9ac858c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +nginx (1.22.0-3) UNRELEASED; urgency=medium + + * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) + + -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 + nginx (1.22.0-2) unstable; urgency=medium [ Miao Wang ] @@ -8,7 +14,7 @@ nginx (1.22.0-2) unstable; urgency=medium * d/nginx-common.nginx.service: added Systemd dependency Wants=network-online.target and updated Systemd "After" dependency to recommended NGINX values, namely: - - network-online.target (Closes: 61261) (Closes: 1000406) + - network-online.target (Closes: 861261) (Closes: 1000406) - remote-fs.target (Closes: 898896) - nss-lookup.target * d/p/0003-define_gnu_source-on-other-glibc-based-platforms.patch: forwarded From caf389149afa0b5923116bc4425978a179829c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:32:23 +0200 Subject: [PATCH 235/414] d/p/nginx-ssl_cert_cb_yield.patch add --- debian/changelog | 1 + debian/patches/nginx-ssl_cert_cb_yield.patch | 40 ++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 42 insertions(+) create mode 100644 debian/patches/nginx-ssl_cert_cb_yield.patch diff --git a/debian/changelog b/debian/changelog index 9ac858c..a41d64e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ nginx (1.22.0-3) UNRELEASED; urgency=medium * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) + * d/p/nginx-ssl_cert_cb_yield.patch added (Closes: 884434) -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 diff --git a/debian/patches/nginx-ssl_cert_cb_yield.patch b/debian/patches/nginx-ssl_cert_cb_yield.patch new file mode 100644 index 0000000..96e06e1 --- /dev/null +++ b/debian/patches/nginx-ssl_cert_cb_yield.patch @@ -0,0 +1,40 @@ +Description: SSL: handled SSL_CTX_set_cert_cb() callback yielding. +Author: Yichun Zhang +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=884434 +Origin: https://raw.githubusercontent.com/openresty/openresty/v1.11.2.2/patches/nginx-1.11.2-ssl_cert_cb_yield.patch +Last-Update: 2016-01-02 + +OpenSSL 1.0.2+ introduces SSL_CTX_set_cert_cb() to allow custom +callbacks to serve the SSL certificiates and private keys dynamically +and lazily. The callbacks may yield for nonblocking I/O or sleeping. +Here we added support for such usage in NGINX 3rd-party modules +(like ngx_lua) in NGINX's event handlers for downstream SSL +connections. + +diff -r 78b4e10b4367 -r 449f0461859c src/event/ngx_event_openssl.c +--- a/src/event/ngx_event_openssl.c Thu Dec 17 16:39:15 2015 +0300 ++++ b/src/event/ngx_event_openssl.c Sat Jan 02 11:14:44 2016 -0800 +@@ -1210,6 +1210,23 @@ + return NGX_AGAIN; + } + ++#if OPENSSL_VERSION_NUMBER >= 0x10002000L ++ if (sslerr == SSL_ERROR_WANT_X509_LOOKUP) { ++ c->read->handler = ngx_ssl_handshake_handler; ++ c->write->handler = ngx_ssl_handshake_handler; ++ ++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ if (ngx_handle_write_event(c->write, 0) != NGX_OK) { ++ return NGX_ERROR; ++ } ++ ++ return NGX_AGAIN; ++ } ++#endif ++ + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + c->ssl->no_wait_shutdown = 1; diff --git a/debian/patches/series b/debian/patches/series index 5e15dcc..52e1dc4 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1,3 @@ 0003-define_gnu_source-on-other-glibc-based-platforms.patch nginx-fix-pidfile.patch +nginx-ssl_cert_cb_yield.patch From 212327ed576d26fc3b35feb30a43079d10fc5cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Moj=C5=BE=C3=AD=C5=A1?= Date: Mon, 8 Aug 2022 12:34:00 +0200 Subject: [PATCH 236/414] http-lua: remove --- debian/changelog | 1 + debian/control | 18 +- debian/copyright | 9 - debian/libnginx-mod-http-lua.nginx | 13 - debian/modules/http-lua/README.markdown | 8332 ----------------- debian/modules/http-lua/config | 532 -- .../modules/http-lua/doc/HttpLuaModule.wiki | 7073 -------------- .../http-lua/dtrace/ngx_lua_provider.d | 61 - .../http-lua/misc/recv-until-pm/Makefile | 3 - .../misc/recv-until-pm/lib/RecvUntil.pm | 138 - .../http-lua/misc/recv-until-pm/t/sanity.t | 140 - .../http-lua/src/api/ngx_http_lua_api.h | 62 - debian/modules/http-lua/src/ddebug.h | 85 - .../http-lua/src/ngx_http_lua_accessby.c | 398 - .../http-lua/src/ngx_http_lua_accessby.h | 22 - .../modules/http-lua/src/ngx_http_lua_api.c | 216 - .../modules/http-lua/src/ngx_http_lua_args.c | 555 -- .../modules/http-lua/src/ngx_http_lua_args.h | 20 - .../http-lua/src/ngx_http_lua_balancer.c | 763 -- .../http-lua/src/ngx_http_lua_balancer.h | 27 - .../http-lua/src/ngx_http_lua_bodyfilterby.c | 633 -- .../http-lua/src/ngx_http_lua_bodyfilterby.h | 31 - .../modules/http-lua/src/ngx_http_lua_cache.c | 296 - .../modules/http-lua/src/ngx_http_lua_cache.h | 24 - .../http-lua/src/ngx_http_lua_capturefilter.c | 176 - .../http-lua/src/ngx_http_lua_capturefilter.h | 20 - .../http-lua/src/ngx_http_lua_clfactory.c | 887 -- .../http-lua/src/ngx_http_lua_clfactory.h | 22 - .../http-lua/src/ngx_http_lua_common.h | 593 -- .../http-lua/src/ngx_http_lua_config.c | 70 - .../http-lua/src/ngx_http_lua_config.h | 19 - .../http-lua/src/ngx_http_lua_consts.c | 202 - .../http-lua/src/ngx_http_lua_consts.h | 20 - .../http-lua/src/ngx_http_lua_contentby.c | 387 - .../http-lua/src/ngx_http_lua_contentby.h | 26 - .../http-lua/src/ngx_http_lua_control.c | 555 -- .../http-lua/src/ngx_http_lua_control.h | 20 - .../http-lua/src/ngx_http_lua_coroutine.c | 387 - .../http-lua/src/ngx_http_lua_coroutine.h | 23 - .../modules/http-lua/src/ngx_http_lua_ctx.c | 216 - .../modules/http-lua/src/ngx_http_lua_ctx.h | 23 - .../http-lua/src/ngx_http_lua_directive.c | 1831 ---- .../http-lua/src/ngx_http_lua_directive.h | 78 - .../http-lua/src/ngx_http_lua_exception.c | 58 - .../http-lua/src/ngx_http_lua_exception.h | 33 - .../src/ngx_http_lua_headerfilterby.c | 302 - .../src/ngx_http_lua_headerfilterby.h | 29 - .../http-lua/src/ngx_http_lua_headers.c | 1529 --- .../http-lua/src/ngx_http_lua_headers.h | 25 - .../http-lua/src/ngx_http_lua_headers_in.c | 835 -- .../http-lua/src/ngx_http_lua_headers_in.h | 22 - .../http-lua/src/ngx_http_lua_headers_out.c | 637 -- .../http-lua/src/ngx_http_lua_headers_out.h | 23 - .../http-lua/src/ngx_http_lua_initby.c | 42 - .../http-lua/src/ngx_http_lua_initby.h | 23 - .../http-lua/src/ngx_http_lua_initworkerby.c | 357 - .../http-lua/src/ngx_http_lua_initworkerby.h | 25 - .../modules/http-lua/src/ngx_http_lua_lex.c | 8251 ---------------- .../modules/http-lua/src/ngx_http_lua_lex.h | 17 - .../modules/http-lua/src/ngx_http_lua_log.c | 456 - .../modules/http-lua/src/ngx_http_lua_log.h | 24 - .../http-lua/src/ngx_http_lua_log_ringbuf.c | 225 - .../http-lua/src/ngx_http_lua_log_ringbuf.h | 31 - .../modules/http-lua/src/ngx_http_lua_logby.c | 266 - .../modules/http-lua/src/ngx_http_lua_logby.h | 22 - .../modules/http-lua/src/ngx_http_lua_misc.c | 292 - .../modules/http-lua/src/ngx_http_lua_misc.h | 22 - .../http-lua/src/ngx_http_lua_module.c | 1312 --- .../modules/http-lua/src/ngx_http_lua_ndk.c | 191 - .../modules/http-lua/src/ngx_http_lua_ndk.h | 21 - .../http-lua/src/ngx_http_lua_output.c | 808 -- .../http-lua/src/ngx_http_lua_output.h | 28 - .../http-lua/src/ngx_http_lua_pcrefix.c | 106 - .../http-lua/src/ngx_http_lua_pcrefix.h | 23 - .../modules/http-lua/src/ngx_http_lua_phase.c | 128 - .../modules/http-lua/src/ngx_http_lua_phase.h | 13 - .../modules/http-lua/src/ngx_http_lua_probe.h | 86 - .../modules/http-lua/src/ngx_http_lua_regex.c | 2548 ----- .../modules/http-lua/src/ngx_http_lua_regex.h | 24 - .../http-lua/src/ngx_http_lua_req_body.c | 1188 --- .../http-lua/src/ngx_http_lua_req_body.h | 20 - .../http-lua/src/ngx_http_lua_req_method.c | 253 - .../http-lua/src/ngx_http_lua_req_method.h | 19 - .../http-lua/src/ngx_http_lua_rewriteby.c | 380 - .../http-lua/src/ngx_http_lua_rewriteby.h | 22 - .../http-lua/src/ngx_http_lua_script.c | 538 -- .../http-lua/src/ngx_http_lua_script.h | 86 - .../http-lua/src/ngx_http_lua_semaphore.c | 578 -- .../http-lua/src/ngx_http_lua_semaphore.h | 53 - .../modules/http-lua/src/ngx_http_lua_setby.c | 216 - .../modules/http-lua/src/ngx_http_lua_setby.h | 15 - .../http-lua/src/ngx_http_lua_shdict.c | 3027 ------ .../http-lua/src/ngx_http_lua_shdict.h | 67 - .../modules/http-lua/src/ngx_http_lua_sleep.c | 219 - .../modules/http-lua/src/ngx_http_lua_sleep.h | 20 - .../http-lua/src/ngx_http_lua_socket_tcp.c | 5521 ----------- .../http-lua/src/ngx_http_lua_socket_tcp.h | 156 - .../http-lua/src/ngx_http_lua_socket_udp.c | 1657 ---- .../http-lua/src/ngx_http_lua_socket_udp.h | 65 - .../modules/http-lua/src/ngx_http_lua_ssl.c | 37 - .../modules/http-lua/src/ngx_http_lua_ssl.h | 47 - .../http-lua/src/ngx_http_lua_ssl_certby.c | 1325 --- .../http-lua/src/ngx_http_lua_ssl_certby.h | 37 - .../http-lua/src/ngx_http_lua_ssl_ocsp.c | 506 - .../src/ngx_http_lua_ssl_session_fetchby.c | 614 -- .../src/ngx_http_lua_ssl_session_fetchby.h | 38 - .../src/ngx_http_lua_ssl_session_storeby.c | 618 -- .../src/ngx_http_lua_ssl_session_storeby.h | 34 - .../http-lua/src/ngx_http_lua_string.c | 767 -- .../http-lua/src/ngx_http_lua_string.h | 20 - .../http-lua/src/ngx_http_lua_subrequest.c | 1782 ---- .../http-lua/src/ngx_http_lua_subrequest.h | 46 - .../modules/http-lua/src/ngx_http_lua_time.c | 349 - .../modules/http-lua/src/ngx_http_lua_time.h | 21 - .../modules/http-lua/src/ngx_http_lua_timer.c | 909 -- .../modules/http-lua/src/ngx_http_lua_timer.h | 20 - .../modules/http-lua/src/ngx_http_lua_uri.c | 110 - .../modules/http-lua/src/ngx_http_lua_uri.h | 20 - .../http-lua/src/ngx_http_lua_uthread.c | 285 - .../http-lua/src/ngx_http_lua_uthread.h | 36 - .../modules/http-lua/src/ngx_http_lua_util.c | 4132 -------- .../modules/http-lua/src/ngx_http_lua_util.h | 468 - .../http-lua/src/ngx_http_lua_variable.c | 509 - .../http-lua/src/ngx_http_lua_variable.h | 20 - .../http-lua/src/ngx_http_lua_worker.c | 193 - .../http-lua/src/ngx_http_lua_worker.h | 17 - debian/modules/http-lua/t/000--init.t | 85 - debian/modules/http-lua/t/000-sanity.t | 33 - debian/modules/http-lua/t/001-set.t | 797 -- debian/modules/http-lua/t/002-content.t | 844 -- debian/modules/http-lua/t/003-errors.t | 128 - debian/modules/http-lua/t/004-require.t | 211 - debian/modules/http-lua/t/005-exit.t | 725 -- debian/modules/http-lua/t/006-escape.t | 199 - debian/modules/http-lua/t/007-md5.t | 102 - debian/modules/http-lua/t/008-today.t | 38 - debian/modules/http-lua/t/009-log.t | 544 -- debian/modules/http-lua/t/010-request_body.t | 272 - debian/modules/http-lua/t/011-md5_bin.t | 170 - debian/modules/http-lua/t/012-now.t | 118 - debian/modules/http-lua/t/013-base64.t | 245 - debian/modules/http-lua/t/014-bugs.t | 1020 -- debian/modules/http-lua/t/015-status.t | 293 - debian/modules/http-lua/t/016-resp-header.t | 1701 ---- debian/modules/http-lua/t/017-exec.t | 596 -- debian/modules/http-lua/t/018-ndk.t | 173 - debian/modules/http-lua/t/019-const.t | 46 - debian/modules/http-lua/t/020-subrequest.t | 2879 ------ debian/modules/http-lua/t/021-cookie-time.t | 45 - debian/modules/http-lua/t/022-redirect.t | 322 - .../http-lua/t/023-rewrite/client-abort.t | 850 -- debian/modules/http-lua/t/023-rewrite/exec.t | 400 - debian/modules/http-lua/t/023-rewrite/exit.t | 597 -- debian/modules/http-lua/t/023-rewrite/mixed.t | 169 - .../http-lua/t/023-rewrite/multi-capture.t | 394 - .../modules/http-lua/t/023-rewrite/on-abort.t | 656 -- .../modules/http-lua/t/023-rewrite/redirect.t | 164 - .../modules/http-lua/t/023-rewrite/req-body.t | 223 - .../http-lua/t/023-rewrite/req-socket.t | 534 -- .../http-lua/t/023-rewrite/request_body.t | 172 - .../modules/http-lua/t/023-rewrite/sanity.t | 801 -- debian/modules/http-lua/t/023-rewrite/sleep.t | 221 - .../http-lua/t/023-rewrite/socket-keepalive.t | 1009 -- .../http-lua/t/023-rewrite/subrequest.t | 641 -- .../t/023-rewrite/tcp-socket-timeout.t | 606 -- .../http-lua/t/023-rewrite/tcp-socket.t | 2392 ----- .../http-lua/t/023-rewrite/unix-socket.t | 152 - .../http-lua/t/023-rewrite/uthread-exec.t | 345 - .../http-lua/t/023-rewrite/uthread-exit.t | 1331 --- .../http-lua/t/023-rewrite/uthread-redirect.t | 188 - .../http-lua/t/023-rewrite/uthread-spawn.t | 1451 --- debian/modules/http-lua/t/024-access/auth.t | 109 - .../http-lua/t/024-access/client-abort.t | 852 -- debian/modules/http-lua/t/024-access/exec.t | 393 - debian/modules/http-lua/t/024-access/exit.t | 547 -- debian/modules/http-lua/t/024-access/mixed.t | 261 - .../http-lua/t/024-access/multi-capture.t | 394 - .../modules/http-lua/t/024-access/on-abort.t | 651 -- .../modules/http-lua/t/024-access/redirect.t | 124 - .../modules/http-lua/t/024-access/req-body.t | 220 - .../http-lua/t/024-access/request_body.t | 172 - debian/modules/http-lua/t/024-access/sanity.t | 743 -- .../modules/http-lua/t/024-access/satisfy.t | 211 - debian/modules/http-lua/t/024-access/sleep.t | 221 - .../http-lua/t/024-access/subrequest.t | 601 -- .../http-lua/t/024-access/uthread-exec.t | 346 - .../http-lua/t/024-access/uthread-exit.t | 1313 --- .../http-lua/t/024-access/uthread-redirect.t | 189 - .../http-lua/t/024-access/uthread-spawn.t | 1118 --- debian/modules/http-lua/t/025-codecache.t | 1246 --- debian/modules/http-lua/t/026-mysql.t | 130 - debian/modules/http-lua/t/027-multi-capture.t | 754 -- debian/modules/http-lua/t/028-req-header.t | 2010 ---- debian/modules/http-lua/t/029-http-time.t | 87 - debian/modules/http-lua/t/030-uri-args.t | 1549 --- debian/modules/http-lua/t/031-post-args.t | 406 - debian/modules/http-lua/t/032-iolist.t | 78 - debian/modules/http-lua/t/033-ctx.t | 442 - debian/modules/http-lua/t/034-match.t | 1192 --- debian/modules/http-lua/t/035-gmatch.t | 904 -- debian/modules/http-lua/t/036-sub.t | 757 -- debian/modules/http-lua/t/037-gsub.t | 699 -- debian/modules/http-lua/t/038-match-o.t | 742 -- debian/modules/http-lua/t/039-sub-o.t | 580 -- debian/modules/http-lua/t/040-gsub-o.t | 200 - debian/modules/http-lua/t/041-header-filter.t | 796 -- debian/modules/http-lua/t/042-crc32.t | 56 - debian/modules/http-lua/t/043-shdict.t | 2473 ----- debian/modules/http-lua/t/044-req-body.t | 1746 ---- debian/modules/http-lua/t/045-ngx-var.t | 230 - debian/modules/http-lua/t/046-hmac.t | 31 - debian/modules/http-lua/t/047-match-jit.t | 214 - debian/modules/http-lua/t/048-match-dfa.t | 209 - debian/modules/http-lua/t/049-gmatch-jit.t | 228 - debian/modules/http-lua/t/050-gmatch-dfa.t | 338 - debian/modules/http-lua/t/051-sub-jit.t | 149 - debian/modules/http-lua/t/052-sub-dfa.t | 235 - debian/modules/http-lua/t/053-gsub-jit.t | 149 - debian/modules/http-lua/t/054-gsub-dfa.t | 236 - debian/modules/http-lua/t/055-subreq-vars.t | 338 - debian/modules/http-lua/t/056-flush.t | 522 -- debian/modules/http-lua/t/057-flush-timeout.t | 320 - debian/modules/http-lua/t/058-tcp-socket.t | 3810 -------- debian/modules/http-lua/t/059-unix-socket.t | 203 - debian/modules/http-lua/t/060-lua-memcached.t | 168 - debian/modules/http-lua/t/061-lua-redis.t | 184 - debian/modules/http-lua/t/062-count.t | 570 -- debian/modules/http-lua/t/063-abort.t | 1019 -- debian/modules/http-lua/t/064-pcall.t | 106 - .../http-lua/t/065-tcp-socket-timeout.t | 1018 -- .../http-lua/t/066-socket-receiveuntil.t | 1331 --- debian/modules/http-lua/t/067-req-socket.t | 1098 --- .../modules/http-lua/t/068-socket-keepalive.t | 1553 --- debian/modules/http-lua/t/069-null.t | 95 - debian/modules/http-lua/t/070-sha1.t | 70 - debian/modules/http-lua/t/071-idle-socket.t | 433 - .../modules/http-lua/t/072-conditional-get.t | 90 - debian/modules/http-lua/t/073-backtrace.t | 189 - debian/modules/http-lua/t/074-prefix-var.t | 66 - debian/modules/http-lua/t/075-logby.t | 583 -- debian/modules/http-lua/t/076-no-postpone.t | 146 - debian/modules/http-lua/t/077-sleep.t | 502 - debian/modules/http-lua/t/078-hup-vars.t | 64 - .../http-lua/t/079-unused-directives.t | 342 - debian/modules/http-lua/t/080-hup-shdict.t | 84 - debian/modules/http-lua/t/081-bytecode.t | 373 - debian/modules/http-lua/t/082-body-filter.t | 839 -- debian/modules/http-lua/t/083-bad-sock-self.t | 138 - .../http-lua/t/084-inclusive-receiveuntil.t | 745 -- debian/modules/http-lua/t/085-if.t | 200 - debian/modules/http-lua/t/086-init-by.t | 323 - debian/modules/http-lua/t/087-udp-socket.t | 1176 --- debian/modules/http-lua/t/088-req-method.t | 264 - debian/modules/http-lua/t/089-phase.t | 178 - .../http-lua/t/090-log-socket-errors.t | 108 - debian/modules/http-lua/t/091-coroutine.t | 1317 --- debian/modules/http-lua/t/092-eof.t | 82 - debian/modules/http-lua/t/093-uthread-spawn.t | 1674 ---- debian/modules/http-lua/t/094-uthread-exit.t | 1650 ---- debian/modules/http-lua/t/095-uthread-exec.t | 425 - .../modules/http-lua/t/096-uthread-redirect.t | 279 - .../modules/http-lua/t/097-uthread-rewrite.t | 347 - debian/modules/http-lua/t/098-uthread-wait.t | 1323 --- debian/modules/http-lua/t/099-c-api.t | 397 - debian/modules/http-lua/t/100-client-abort.t | 1066 --- debian/modules/http-lua/t/101-on-abort.t | 848 -- .../modules/http-lua/t/102-req-start-time.t | 115 - debian/modules/http-lua/t/103-req-http-ver.t | 48 - .../modules/http-lua/t/104-req-raw-header.t | 990 -- debian/modules/http-lua/t/105-pressure.t | 53 - debian/modules/http-lua/t/106-timer.t | 2195 ----- debian/modules/http-lua/t/107-timer-errors.t | 1422 --- debian/modules/http-lua/t/108-timer-safe.t | 1397 --- debian/modules/http-lua/t/109-timer-hup.t | 502 - debian/modules/http-lua/t/110-etag.t | 83 - debian/modules/http-lua/t/111-req-header-ua.t | 675 -- .../modules/http-lua/t/112-req-header-conn.t | 148 - .../http-lua/t/113-req-header-cookie.t | 249 - debian/modules/http-lua/t/114-config.t | 48 - debian/modules/http-lua/t/115-quote-sql-str.t | 76 - .../modules/http-lua/t/116-raw-req-socket.t | 878 -- .../http-lua/t/117-raw-req-socket-timeout.t | 116 - .../modules/http-lua/t/118-use-default-type.t | 140 - debian/modules/http-lua/t/119-config-prefix.t | 32 - debian/modules/http-lua/t/120-re-find.t | 919 -- debian/modules/http-lua/t/121-version.t | 48 - debian/modules/http-lua/t/122-worker.t | 81 - debian/modules/http-lua/t/123-lua-path.t | 70 - debian/modules/http-lua/t/124-init-worker.t | 955 -- .../modules/http-lua/t/125-configure-args.t | 31 - debian/modules/http-lua/t/126-shdict-frag.t | 1266 --- debian/modules/http-lua/t/127-uthread-kill.t | 507 - .../http-lua/t/128-duplex-tcp-socket.t | 631 -- debian/modules/http-lua/t/129-ssl-socket.t | 2532 ----- debian/modules/http-lua/t/130-internal-api.t | 49 - .../http-lua/t/131-duplex-req-socket.t | 141 - debian/modules/http-lua/t/132-lua-blocks.t | 729 -- debian/modules/http-lua/t/133-worker-count.t | 72 - .../modules/http-lua/t/134-worker-count-5.t | 78 - debian/modules/http-lua/t/135-worker-id.t | 33 - debian/modules/http-lua/t/136-timer-counts.t | 111 - debian/modules/http-lua/t/137-req-misc.t | 61 - debian/modules/http-lua/t/138-balancer.t | 528 -- debian/modules/http-lua/t/139-ssl-cert-by.t | 2077 ---- debian/modules/http-lua/t/140-ssl-c-api.t | 813 -- debian/modules/http-lua/t/141-luajit.t | 48 - .../http-lua/t/142-ssl-session-store.t | 903 -- .../http-lua/t/143-ssl-session-fetch.t | 1116 --- .../modules/http-lua/t/144-shdict-incr-init.t | 226 - debian/modules/http-lua/t/145-shdict-list.t | 745 -- debian/modules/http-lua/t/146-malloc-trim.t | 342 - .../http-lua/t/147-tcp-socket-timeouts.t | 627 -- debian/modules/http-lua/t/148-fake-shm-zone.t | 170 - .../http-lua/t/149-hup-fake-shm-zone.t | 91 - .../http-lua/t/150-fake-delayed-load.t | 56 - debian/modules/http-lua/t/151-initby-hup.t | 168 - debian/modules/http-lua/t/152-timer-every.t | 385 - debian/modules/http-lua/t/153-semaphore-hup.t | 154 - debian/modules/http-lua/t/154-semaphore.t | 120 - debian/modules/http-lua/t/155-tls13.t | 106 - debian/modules/http-lua/t/StapThread.pm | 282 - debian/modules/http-lua/t/cert/dst-ca.crt | 63 - debian/modules/http-lua/t/cert/equifax.crt | 19 - debian/modules/http-lua/t/cert/test.crl | 11 - debian/modules/http-lua/t/cert/test.crt | 17 - debian/modules/http-lua/t/cert/test.key | 15 - debian/modules/http-lua/t/cert/test2.crt | 16 - debian/modules/http-lua/t/cert/test2.key | 15 - debian/modules/http-lua/t/cert/test_ecdsa.crt | 12 - debian/modules/http-lua/t/cert/test_ecdsa.key | 5 - .../t/data/fake-delayed-load-module/config | 3 - .../ngx_http_lua_fake_delayed_load_module.c | 77 - .../http-lua/t/data/fake-module/config | 3 - .../t/data/fake-module/ngx_http_fake_module.c | 118 - .../http-lua/t/data/fake-shm-module/config | 3 - .../ngx_http_lua_fake_shm_module.c | 294 - debian/modules/http-lua/t/lib/CRC32.lua | 173 - debian/modules/http-lua/t/lib/Memcached.lua | 567 -- debian/modules/http-lua/t/lib/Redis.lua | 1120 --- debian/modules/http-lua/t/lib/ljson.lua | 89 - debian/modules/http-lua/tapset/ngx_lua.stp | 5 - debian/modules/http-lua/util/build.sh | 66 - debian/modules/http-lua/util/fix-comments | 27 - debian/modules/http-lua/util/gen-lexer-c | 18 - debian/modules/http-lua/util/ngx-links | 62 - debian/modules/http-lua/util/releng | 8 - debian/modules/http-lua/util/retab | 8 - debian/modules/http-lua/util/revim | 102 - debian/modules/http-lua/util/run_test.sh | 10 - debian/modules/http-lua/util/update-readme.sh | 4 - debian/modules/http-lua/valgrind.suppress | 209 - .../patches/http-lua/CVE-2020-11724.patch | 856 -- .../http-lua/bug-994178-segfault.patch | 31 - .../http-lua/discover-luajit-2.1.patch | 47 - debian/modules/patches/http-lua/series | 3 - debian/rules | 2 - debian/tests/control | 12 +- debian/tests/lua | 18 - 358 files changed, 6 insertions(+), 182310 deletions(-) delete mode 100755 debian/libnginx-mod-http-lua.nginx delete mode 100644 debian/modules/http-lua/README.markdown delete mode 100644 debian/modules/http-lua/config delete mode 100644 debian/modules/http-lua/doc/HttpLuaModule.wiki delete mode 100644 debian/modules/http-lua/dtrace/ngx_lua_provider.d delete mode 100644 debian/modules/http-lua/misc/recv-until-pm/Makefile delete mode 100755 debian/modules/http-lua/misc/recv-until-pm/lib/RecvUntil.pm delete mode 100644 debian/modules/http-lua/misc/recv-until-pm/t/sanity.t delete mode 100644 debian/modules/http-lua/src/api/ngx_http_lua_api.h delete mode 100644 debian/modules/http-lua/src/ddebug.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_accessby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_accessby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_api.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_args.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_args.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_balancer.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_balancer.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_bodyfilterby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_cache.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_cache.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_capturefilter.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_capturefilter.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_clfactory.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_clfactory.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_common.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_config.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_config.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_consts.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_consts.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_contentby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_contentby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_control.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_control.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_coroutine.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_coroutine.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ctx.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ctx.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_directive.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_directive.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_exception.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_exception.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headerfilterby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headerfilterby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_in.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_in.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_out.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_headers_out.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initworkerby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_initworkerby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_lex.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_lex.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_log_ringbuf.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_logby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_logby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_misc.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_misc.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_module.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ndk.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ndk.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_output.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_output.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pcrefix.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_pcrefix.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_phase.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_phase.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_probe.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_regex.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_regex.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_body.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_body.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_method.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_req_method.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_rewriteby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_rewriteby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_script.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_script.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_semaphore.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_semaphore.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_setby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_setby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_shdict.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_shdict.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_sleep.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_sleep.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_tcp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_tcp.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_udp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_socket_udp.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_certby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_certby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_ocsp.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_fetchby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_ssl_session_storeby.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_string.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_string.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_subrequest.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_subrequest.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_time.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_time.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_timer.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_timer.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uri.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uri.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uthread.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_uthread.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_util.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_util.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_variable.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_variable.h delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_worker.c delete mode 100644 debian/modules/http-lua/src/ngx_http_lua_worker.h delete mode 100644 debian/modules/http-lua/t/000--init.t delete mode 100644 debian/modules/http-lua/t/000-sanity.t delete mode 100644 debian/modules/http-lua/t/001-set.t delete mode 100644 debian/modules/http-lua/t/002-content.t delete mode 100644 debian/modules/http-lua/t/003-errors.t delete mode 100644 debian/modules/http-lua/t/004-require.t delete mode 100644 debian/modules/http-lua/t/005-exit.t delete mode 100644 debian/modules/http-lua/t/006-escape.t delete mode 100644 debian/modules/http-lua/t/007-md5.t delete mode 100644 debian/modules/http-lua/t/008-today.t delete mode 100644 debian/modules/http-lua/t/009-log.t delete mode 100644 debian/modules/http-lua/t/010-request_body.t delete mode 100644 debian/modules/http-lua/t/011-md5_bin.t delete mode 100644 debian/modules/http-lua/t/012-now.t delete mode 100644 debian/modules/http-lua/t/013-base64.t delete mode 100644 debian/modules/http-lua/t/014-bugs.t delete mode 100644 debian/modules/http-lua/t/015-status.t delete mode 100644 debian/modules/http-lua/t/016-resp-header.t delete mode 100644 debian/modules/http-lua/t/017-exec.t delete mode 100644 debian/modules/http-lua/t/018-ndk.t delete mode 100644 debian/modules/http-lua/t/019-const.t delete mode 100644 debian/modules/http-lua/t/020-subrequest.t delete mode 100644 debian/modules/http-lua/t/021-cookie-time.t delete mode 100644 debian/modules/http-lua/t/022-redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/client-abort.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/exec.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/exit.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/mixed.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/multi-capture.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/on-abort.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/req-body.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/req-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/request_body.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/sanity.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/sleep.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/socket-keepalive.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/subrequest.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/tcp-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/tcp-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/unix-socket.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-exec.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-exit.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/023-rewrite/uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/024-access/auth.t delete mode 100644 debian/modules/http-lua/t/024-access/client-abort.t delete mode 100644 debian/modules/http-lua/t/024-access/exec.t delete mode 100644 debian/modules/http-lua/t/024-access/exit.t delete mode 100644 debian/modules/http-lua/t/024-access/mixed.t delete mode 100644 debian/modules/http-lua/t/024-access/multi-capture.t delete mode 100644 debian/modules/http-lua/t/024-access/on-abort.t delete mode 100644 debian/modules/http-lua/t/024-access/redirect.t delete mode 100644 debian/modules/http-lua/t/024-access/req-body.t delete mode 100644 debian/modules/http-lua/t/024-access/request_body.t delete mode 100644 debian/modules/http-lua/t/024-access/sanity.t delete mode 100644 debian/modules/http-lua/t/024-access/satisfy.t delete mode 100644 debian/modules/http-lua/t/024-access/sleep.t delete mode 100644 debian/modules/http-lua/t/024-access/subrequest.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-exec.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-exit.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/024-access/uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/025-codecache.t delete mode 100644 debian/modules/http-lua/t/026-mysql.t delete mode 100644 debian/modules/http-lua/t/027-multi-capture.t delete mode 100644 debian/modules/http-lua/t/028-req-header.t delete mode 100644 debian/modules/http-lua/t/029-http-time.t delete mode 100644 debian/modules/http-lua/t/030-uri-args.t delete mode 100644 debian/modules/http-lua/t/031-post-args.t delete mode 100644 debian/modules/http-lua/t/032-iolist.t delete mode 100644 debian/modules/http-lua/t/033-ctx.t delete mode 100644 debian/modules/http-lua/t/034-match.t delete mode 100644 debian/modules/http-lua/t/035-gmatch.t delete mode 100644 debian/modules/http-lua/t/036-sub.t delete mode 100644 debian/modules/http-lua/t/037-gsub.t delete mode 100644 debian/modules/http-lua/t/038-match-o.t delete mode 100644 debian/modules/http-lua/t/039-sub-o.t delete mode 100644 debian/modules/http-lua/t/040-gsub-o.t delete mode 100644 debian/modules/http-lua/t/041-header-filter.t delete mode 100644 debian/modules/http-lua/t/042-crc32.t delete mode 100644 debian/modules/http-lua/t/043-shdict.t delete mode 100644 debian/modules/http-lua/t/044-req-body.t delete mode 100644 debian/modules/http-lua/t/045-ngx-var.t delete mode 100644 debian/modules/http-lua/t/046-hmac.t delete mode 100644 debian/modules/http-lua/t/047-match-jit.t delete mode 100644 debian/modules/http-lua/t/048-match-dfa.t delete mode 100644 debian/modules/http-lua/t/049-gmatch-jit.t delete mode 100644 debian/modules/http-lua/t/050-gmatch-dfa.t delete mode 100644 debian/modules/http-lua/t/051-sub-jit.t delete mode 100644 debian/modules/http-lua/t/052-sub-dfa.t delete mode 100644 debian/modules/http-lua/t/053-gsub-jit.t delete mode 100644 debian/modules/http-lua/t/054-gsub-dfa.t delete mode 100644 debian/modules/http-lua/t/055-subreq-vars.t delete mode 100644 debian/modules/http-lua/t/056-flush.t delete mode 100644 debian/modules/http-lua/t/057-flush-timeout.t delete mode 100644 debian/modules/http-lua/t/058-tcp-socket.t delete mode 100644 debian/modules/http-lua/t/059-unix-socket.t delete mode 100644 debian/modules/http-lua/t/060-lua-memcached.t delete mode 100644 debian/modules/http-lua/t/061-lua-redis.t delete mode 100644 debian/modules/http-lua/t/062-count.t delete mode 100644 debian/modules/http-lua/t/063-abort.t delete mode 100644 debian/modules/http-lua/t/064-pcall.t delete mode 100644 debian/modules/http-lua/t/065-tcp-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/066-socket-receiveuntil.t delete mode 100644 debian/modules/http-lua/t/067-req-socket.t delete mode 100644 debian/modules/http-lua/t/068-socket-keepalive.t delete mode 100644 debian/modules/http-lua/t/069-null.t delete mode 100644 debian/modules/http-lua/t/070-sha1.t delete mode 100644 debian/modules/http-lua/t/071-idle-socket.t delete mode 100644 debian/modules/http-lua/t/072-conditional-get.t delete mode 100644 debian/modules/http-lua/t/073-backtrace.t delete mode 100644 debian/modules/http-lua/t/074-prefix-var.t delete mode 100644 debian/modules/http-lua/t/075-logby.t delete mode 100644 debian/modules/http-lua/t/076-no-postpone.t delete mode 100644 debian/modules/http-lua/t/077-sleep.t delete mode 100644 debian/modules/http-lua/t/078-hup-vars.t delete mode 100644 debian/modules/http-lua/t/079-unused-directives.t delete mode 100644 debian/modules/http-lua/t/080-hup-shdict.t delete mode 100644 debian/modules/http-lua/t/081-bytecode.t delete mode 100644 debian/modules/http-lua/t/082-body-filter.t delete mode 100644 debian/modules/http-lua/t/083-bad-sock-self.t delete mode 100644 debian/modules/http-lua/t/084-inclusive-receiveuntil.t delete mode 100644 debian/modules/http-lua/t/085-if.t delete mode 100644 debian/modules/http-lua/t/086-init-by.t delete mode 100644 debian/modules/http-lua/t/087-udp-socket.t delete mode 100644 debian/modules/http-lua/t/088-req-method.t delete mode 100644 debian/modules/http-lua/t/089-phase.t delete mode 100644 debian/modules/http-lua/t/090-log-socket-errors.t delete mode 100644 debian/modules/http-lua/t/091-coroutine.t delete mode 100644 debian/modules/http-lua/t/092-eof.t delete mode 100644 debian/modules/http-lua/t/093-uthread-spawn.t delete mode 100644 debian/modules/http-lua/t/094-uthread-exit.t delete mode 100644 debian/modules/http-lua/t/095-uthread-exec.t delete mode 100644 debian/modules/http-lua/t/096-uthread-redirect.t delete mode 100644 debian/modules/http-lua/t/097-uthread-rewrite.t delete mode 100644 debian/modules/http-lua/t/098-uthread-wait.t delete mode 100644 debian/modules/http-lua/t/099-c-api.t delete mode 100644 debian/modules/http-lua/t/100-client-abort.t delete mode 100644 debian/modules/http-lua/t/101-on-abort.t delete mode 100644 debian/modules/http-lua/t/102-req-start-time.t delete mode 100644 debian/modules/http-lua/t/103-req-http-ver.t delete mode 100644 debian/modules/http-lua/t/104-req-raw-header.t delete mode 100644 debian/modules/http-lua/t/105-pressure.t delete mode 100644 debian/modules/http-lua/t/106-timer.t delete mode 100644 debian/modules/http-lua/t/107-timer-errors.t delete mode 100644 debian/modules/http-lua/t/108-timer-safe.t delete mode 100644 debian/modules/http-lua/t/109-timer-hup.t delete mode 100644 debian/modules/http-lua/t/110-etag.t delete mode 100644 debian/modules/http-lua/t/111-req-header-ua.t delete mode 100644 debian/modules/http-lua/t/112-req-header-conn.t delete mode 100644 debian/modules/http-lua/t/113-req-header-cookie.t delete mode 100644 debian/modules/http-lua/t/114-config.t delete mode 100644 debian/modules/http-lua/t/115-quote-sql-str.t delete mode 100644 debian/modules/http-lua/t/116-raw-req-socket.t delete mode 100644 debian/modules/http-lua/t/117-raw-req-socket-timeout.t delete mode 100644 debian/modules/http-lua/t/118-use-default-type.t delete mode 100644 debian/modules/http-lua/t/119-config-prefix.t delete mode 100644 debian/modules/http-lua/t/120-re-find.t delete mode 100644 debian/modules/http-lua/t/121-version.t delete mode 100644 debian/modules/http-lua/t/122-worker.t delete mode 100644 debian/modules/http-lua/t/123-lua-path.t delete mode 100644 debian/modules/http-lua/t/124-init-worker.t delete mode 100644 debian/modules/http-lua/t/125-configure-args.t delete mode 100644 debian/modules/http-lua/t/126-shdict-frag.t delete mode 100644 debian/modules/http-lua/t/127-uthread-kill.t delete mode 100644 debian/modules/http-lua/t/128-duplex-tcp-socket.t delete mode 100644 debian/modules/http-lua/t/129-ssl-socket.t delete mode 100644 debian/modules/http-lua/t/130-internal-api.t delete mode 100644 debian/modules/http-lua/t/131-duplex-req-socket.t delete mode 100644 debian/modules/http-lua/t/132-lua-blocks.t delete mode 100644 debian/modules/http-lua/t/133-worker-count.t delete mode 100644 debian/modules/http-lua/t/134-worker-count-5.t delete mode 100644 debian/modules/http-lua/t/135-worker-id.t delete mode 100644 debian/modules/http-lua/t/136-timer-counts.t delete mode 100644 debian/modules/http-lua/t/137-req-misc.t delete mode 100644 debian/modules/http-lua/t/138-balancer.t delete mode 100644 debian/modules/http-lua/t/139-ssl-cert-by.t delete mode 100644 debian/modules/http-lua/t/140-ssl-c-api.t delete mode 100644 debian/modules/http-lua/t/141-luajit.t delete mode 100644 debian/modules/http-lua/t/142-ssl-session-store.t delete mode 100644 debian/modules/http-lua/t/143-ssl-session-fetch.t delete mode 100644 debian/modules/http-lua/t/144-shdict-incr-init.t delete mode 100644 debian/modules/http-lua/t/145-shdict-list.t delete mode 100644 debian/modules/http-lua/t/146-malloc-trim.t delete mode 100644 debian/modules/http-lua/t/147-tcp-socket-timeouts.t delete mode 100644 debian/modules/http-lua/t/148-fake-shm-zone.t delete mode 100644 debian/modules/http-lua/t/149-hup-fake-shm-zone.t delete mode 100644 debian/modules/http-lua/t/150-fake-delayed-load.t delete mode 100644 debian/modules/http-lua/t/151-initby-hup.t delete mode 100644 debian/modules/http-lua/t/152-timer-every.t delete mode 100644 debian/modules/http-lua/t/153-semaphore-hup.t delete mode 100644 debian/modules/http-lua/t/154-semaphore.t delete mode 100644 debian/modules/http-lua/t/155-tls13.t delete mode 100644 debian/modules/http-lua/t/StapThread.pm delete mode 100644 debian/modules/http-lua/t/cert/dst-ca.crt delete mode 100644 debian/modules/http-lua/t/cert/equifax.crt delete mode 100644 debian/modules/http-lua/t/cert/test.crl delete mode 100644 debian/modules/http-lua/t/cert/test.crt delete mode 100644 debian/modules/http-lua/t/cert/test.key delete mode 100644 debian/modules/http-lua/t/cert/test2.crt delete mode 100644 debian/modules/http-lua/t/cert/test2.key delete mode 100644 debian/modules/http-lua/t/cert/test_ecdsa.crt delete mode 100644 debian/modules/http-lua/t/cert/test_ecdsa.key delete mode 100644 debian/modules/http-lua/t/data/fake-delayed-load-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-delayed-load-module/ngx_http_lua_fake_delayed_load_module.c delete mode 100644 debian/modules/http-lua/t/data/fake-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-module/ngx_http_fake_module.c delete mode 100644 debian/modules/http-lua/t/data/fake-shm-module/config delete mode 100644 debian/modules/http-lua/t/data/fake-shm-module/ngx_http_lua_fake_shm_module.c delete mode 100755 debian/modules/http-lua/t/lib/CRC32.lua delete mode 100755 debian/modules/http-lua/t/lib/Memcached.lua delete mode 100644 debian/modules/http-lua/t/lib/Redis.lua delete mode 100644 debian/modules/http-lua/t/lib/ljson.lua delete mode 100644 debian/modules/http-lua/tapset/ngx_lua.stp delete mode 100755 debian/modules/http-lua/util/build.sh delete mode 100644 debian/modules/http-lua/util/fix-comments delete mode 100755 debian/modules/http-lua/util/gen-lexer-c delete mode 100755 debian/modules/http-lua/util/ngx-links delete mode 100755 debian/modules/http-lua/util/releng delete mode 100755 debian/modules/http-lua/util/retab delete mode 100755 debian/modules/http-lua/util/revim delete mode 100755 debian/modules/http-lua/util/run_test.sh delete mode 100755 debian/modules/http-lua/util/update-readme.sh delete mode 100644 debian/modules/http-lua/valgrind.suppress delete mode 100644 debian/modules/patches/http-lua/CVE-2020-11724.patch delete mode 100644 debian/modules/patches/http-lua/bug-994178-segfault.patch delete mode 100644 debian/modules/patches/http-lua/discover-luajit-2.1.patch delete mode 100644 debian/modules/patches/http-lua/series delete mode 100644 debian/tests/lua diff --git a/debian/changelog b/debian/changelog index a41d64e..fff7b8f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ nginx (1.22.0-3) UNRELEASED; urgency=medium * d/changelog: fixed typo in bug number 61261 -> 861261 (Closes: 861261) * d/p/nginx-ssl_cert_cb_yield.patch added (Closes: 884434) + * http-lua: removed the http-lua module and moved it to a separate package -- Jan Mojžíš Mon, 08 Aug 2022 12:29:34 +0200 diff --git a/debian/control b/debian/control index c8aa03c..206523f 100644 --- a/debian/control +++ b/debian/control @@ -11,8 +11,6 @@ Build-Depends: debhelper-compat (= 13), libgd-dev, libgeoip-dev, libhiredis-dev, - liblua5.1-0-dev [!i386 !amd64 !kfreebsd-i386 !kfreebsd-amd64 !armel !armhf !powerpc !powerpcspe !mips !mipsel !mips64el !arm64 !ppc64 !s390x], - libluajit-5.1-dev [i386 amd64 kfreebsd-i386 kfreebsd-amd64 armel armhf powerpc powerpcspe mips mipsel mips64el arm64 ppc64 s390x], libmaxminddb-dev, libmhash-dev, libpam0g-dev, @@ -209,7 +207,7 @@ Depends: libnginx-mod-http-auth-pam (= ${binary:Version}), libnginx-mod-http-geoip2 (= ${binary:Version}), libnginx-mod-http-headers-more-filter (= ${binary:Version}), libnginx-mod-http-image-filter (= ${binary:Version}), - libnginx-mod-http-lua (= ${binary:Version}), + libnginx-mod-http-lua [amd64 arm64 armel armhf i386 mips64el mipsel s390x], libnginx-mod-http-perl (= ${binary:Version}), libnginx-mod-http-subs-filter (= ${binary:Version}), libnginx-mod-http-uploadprogress (= ${binary:Version}), @@ -364,20 +362,6 @@ Description: PAM authentication module for Nginx The module uses PAM as a backend for simple http authentication. It also allows setting the pam service name to allow more fine grained control. -Package: libnginx-mod-http-lua -Architecture: any -Depends: libnginx-mod-http-ndk (= ${binary:Version}), - ${misc:Depends}, - ${shlibs:Depends}, -Recommends: nginx, -Description: Lua module for Nginx - Embed Lua runtime into nginx. - . - This module embeds Lua, via the standard Lua 5.1 interpreter or LuaJIT - 2.0/2.1, into Nginx and by leveraging Nginx's subrequests, allows the - integration of the powerful Lua threads (Lua coroutines) into the Nginx event - model. - Package: libnginx-mod-http-ndk Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, diff --git a/debian/copyright b/debian/copyright index 6449e69..2aabc8d 100644 --- a/debian/copyright +++ b/debian/copyright @@ -84,15 +84,6 @@ Files: debian/modules/http-echo/* Copyright: 2009-2014, Yichun "agentzh" Zhang License: BSD-2-clause -Files: debian/modules/http-lua/* -Copyright: 2009-2017, by Xiaozhe Wang (chaoslawful) . - 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. -License: BSD-2-clause - -Files: debian/modules/http-lua/t/lib/CRC32.lua -Copyright: 2007-2008, Neil Richardson (nrich@iinet.net.au) -License: Expat - Files: debian/modules/http-upstream-fair/* Copyright: 2007, Grzegorz Nosek Igor Sysoev diff --git a/debian/libnginx-mod-http-lua.nginx b/debian/libnginx-mod-http-lua.nginx deleted file mode 100755 index 78c206f..0000000 --- a/debian/libnginx-mod-http-lua.nginx +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/perl -w - -use File::Basename; - -# Guess module name -$module = basename($0, '.nginx'); -$module =~ s/^libnginx-mod-//; - -$modulepath = $module; -$modulepath =~ s/-/_/g; - -print "mod debian/build-extras/objs/ngx_${modulepath}_module.so\n"; -print "mod debian/libnginx-mod.conf/mod-${module}.conf\n"; diff --git a/debian/modules/http-lua/README.markdown b/debian/modules/http-lua/README.markdown deleted file mode 100644 index 15ad00e..0000000 --- a/debian/modules/http-lua/README.markdown +++ /dev/null @@ -1,8332 +0,0 @@ - - -Name -==== - -ngx_http_lua_module - Embed the power of Lua into Nginx HTTP Servers. - -*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) -* [Typical Uses](#typical-uses) -* [Nginx Compatibility](#nginx-compatibility) -* [Installation](#installation) - * [Building as a dynamic module](#building-as-a-dynamic-module) - * [C Macro Configurations](#c-macro-configurations) - * [Installation on Ubuntu 11.10](#installation-on-ubuntu-1110) -* [Community](#community) - * [English Mailing List](#english-mailing-list) - * [Chinese Mailing List](#chinese-mailing-list) -* [Code Repository](#code-repository) -* [Bugs and Patches](#bugs-and-patches) -* [Lua/LuaJIT bytecode support](#lualuajit-bytecode-support) -* [System Environment Variable Support](#system-environment-variable-support) -* [HTTP 1.0 support](#http-10-support) -* [Statically Linking Pure Lua Modules](#statically-linking-pure-lua-modules) -* [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) -* [Known Issues](#known-issues) - * [TCP socket connect operation issues](#tcp-socket-connect-operation-issues) - * [Lua Coroutine Yielding/Resuming](#lua-coroutine-yieldingresuming) - * [Lua Variable Scope](#lua-variable-scope) - * [Locations Configured by Subrequest Directives of Other Modules](#locations-configured-by-subrequest-directives-of-other-modules) - * [Cosockets Not Available Everywhere](#cosockets-not-available-everywhere) - * [Special Escaping Sequences](#special-escaping-sequences) - * [Mixing with SSI Not Supported](#mixing-with-ssi-not-supported) - * [SPDY Mode Not Fully Supported](#spdy-mode-not-fully-supported) - * [Missing data on short circuited requests](#missing-data-on-short-circuited-requests) -* [TODO](#todo) -* [Changes](#changes) -* [Test Suite](#test-suite) -* [Copyright and License](#copyright-and-license) -* [See Also](#see-also) -* [Directives](#directives) -* [Nginx API for Lua](#nginx-api-for-lua) -* [Obsolete Sections](#obsolete-sections) - * [Special PCRE Sequences](#special-pcre-sequences) - -Status -====== - -Production ready. - -Version -======= - -This document describes ngx_lua [v0.10.13](https://github.com/openresty/lua-nginx-module/tags) released on 22 April 2018. - -Synopsis -======== -```nginx - - # set search paths for pure Lua external libraries (';;' is the default path): - lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - - # set search paths for Lua external libraries written in C (can also use ';;'): - lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - - server { - location /lua_content { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua_block { - ngx.say('Hello,world!') - } - } - - location /nginx_var { - # MIME type determined by default_type: - default_type 'text/plain'; - - # try access /nginx_var?a=hello,world - content_by_lua_block { - ngx.say(ngx.var.arg_a) - } - } - - location = /request_body { - client_max_body_size 50k; - client_body_buffer_size 50k; - - content_by_lua_block { - ngx.req.read_body() -- explicitly read the req body - local data = ngx.req.get_body_data() - if data then - ngx.say("body data:") - ngx.print(data) - return - end - - -- body may get buffered in a temp file: - local file = ngx.req.get_body_file() - if file then - ngx.say("body is in file ", file) - else - ngx.say("no body found") - end - } - } - - # transparent non-blocking I/O in Lua via subrequests - # (well, a better way is to use cosockets) - location = /lua { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua_block { - local res = ngx.location.capture("/some_other_location") - if res then - ngx.say("status: ", res.status) - ngx.say("body:") - ngx.print(res.body) - end - } - } - - location = /foo { - rewrite_by_lua_block { - res = ngx.location.capture("/memc", - { args = { cmd = "incr", key = ngx.var.uri } } - ) - } - - proxy_pass http://blah.blah.com; - } - - location = /mixed { - rewrite_by_lua_file /path/to/rewrite.lua; - access_by_lua_file /path/to/access.lua; - content_by_lua_file /path/to/content.lua; - } - - # use nginx var in code path - # CAUTION: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/([-_a-zA-Z0-9/]+) { - set $path $1; - content_by_lua_file /path/to/lua/app/root/$path.lua; - } - - location / { - client_max_body_size 100k; - client_body_buffer_size 100k; - - access_by_lua_block { - -- check the client IP address is in our black list - if ngx.var.remote_addr == "132.5.72.3" then - ngx.exit(ngx.HTTP_FORBIDDEN) - end - - -- check if the URI contains bad words - if ngx.var.uri and - string.match(ngx.var.request_body, "evil") - then - return ngx.redirect("/terms_of_use.html") - end - - -- tests passed - } - - # proxy_pass/fastcgi_pass/etc settings - } - } -``` - -[Back to TOC](#table-of-contents) - -Description -=========== - -This module embeds Lua, via the standard Lua 5.1 interpreter or [LuaJIT 2.0/2.1](http://luajit.org/luajit.html), into Nginx and by leveraging Nginx's subrequests, allows the integration of the powerful Lua threads (Lua coroutines) into the Nginx event model. - -Unlike [Apache's mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html) and [Lighttpd's mod_magnet](http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet), Lua code executed using this module can be *100% non-blocking* on network traffic as long as the [Nginx API for Lua](#nginx-api-for-lua) provided by this module is used to handle -requests to upstream services such as MySQL, PostgreSQL, Memcached, Redis, or upstream HTTP web services. - -At least the following Lua libraries and Nginx modules can be used with this ngx_lua module: - -* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) -* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) -* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) -* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) -* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) -* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) -* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) -* [lua-resty-logger-socket](https://github.com/cloudflare/lua-resty-logger-socket) -* [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache) -* [lua-resty-string](https://github.com/openresty/lua-resty-string) -* [ngx_memc](http://github.com/openresty/memc-nginx-module) -* [ngx_postgres](https://github.com/FRiCKLE/ngx_postgres) -* [ngx_redis2](http://github.com/openresty/redis2-nginx-module) -* [ngx_redis](http://wiki.nginx.org/HttpRedisModule) -* [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) -* [ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) - -Almost all the Nginx modules can be used with this ngx_lua module by means of [ngx.location.capture](#ngxlocationcapture) or [ngx.location.capture_multi](#ngxlocationcapture_multi) but it is recommended to use those `lua-resty-*` libraries instead of creating subrequests to access the Nginx upstream modules because the former is usually much more flexible and memory-efficient. - -The Lua interpreter or LuaJIT instance is shared across all the requests in a single nginx worker process but request contexts are segregated using lightweight Lua coroutines. - -Loaded Lua modules persist in the nginx worker process level resulting in a small memory footprint in Lua even when under heavy loads. - -This module is plugged into NGINX's "http" subsystem so it can only speaks downstream communication protocols in the HTTP family (HTTP 0.9/1.0/1.1/2.0, WebSockets, and etc). -If you want to do generic TCP communications with the downstream clients, then you should use the [ngx_stream_lua](https://github.com/openresty/stream-lua-nginx-module#readme) module instead -which has a compatible Lua API. - -[Back to TOC](#table-of-contents) - -Typical Uses -============ - -Just to name a few: - -* Mashup'ing and processing outputs of various nginx upstream outputs (proxy, drizzle, postgres, redis, memcached, and etc) in Lua, -* doing arbitrarily complex access control and security checks in Lua before requests actually reach the upstream backends, -* manipulating response headers in an arbitrary way (by Lua) -* fetching backend information from external storage backends (like redis, memcached, mysql, postgresql) and use that information to choose which upstream backend to access on-the-fly, -* coding up arbitrarily complex web applications in a content handler using synchronous but still non-blocking access to the database backends and other storage, -* doing very complex URL dispatch in Lua at rewrite phase, -* using Lua to implement advanced caching mechanism for Nginx's subrequests and arbitrary locations. - -The possibilities are unlimited as the module allows bringing together various elements within Nginx as well as exposing the power of the Lua language to the user. The module provides the full flexibility of scripting while offering performance levels comparable with native C language programs both in terms of CPU time as well as memory footprint. This is particularly the case when LuaJIT 2.x is enabled. - -Other scripting language implementations typically struggle to match this performance level. - -The Lua state (Lua VM instance) is shared across all the requests handled by a single nginx worker process to minimize memory use. - -[Back to TOC](#table-of-contents) - -Nginx Compatibility -=================== - -The latest version of this module is compatible with the following versions of Nginx: - -* 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 - -Nginx cores older than 1.6.0 (exclusive) are *not* supported. - -[Back to TOC](#table-of-contents) - -Installation -============ - -It is *highly* recommended to use [OpenResty releases](http://openresty.org) which integrate Nginx, ngx_lua, LuaJIT 2.1, as well as other powerful companion Nginx modules and Lua libraries. It is discouraged to build this module with nginx yourself since it is tricky to set up exactly right. Also, the stock nginx cores have various limitations and long standing bugs that can make some of this modules' features become disabled, not work properly, or run slower. The same applies to LuaJIT as well. OpenResty includes its own version of LuaJIT which gets specifically optimized and enhanced for the OpenResty environment. - -Alternatively, ngx_lua can be manually compiled into Nginx: - -1. Install LuaJIT 2.0 or 2.1 (recommended) or Lua 5.1 (Lua 5.2 is *not* supported yet). LuaJIT can be downloaded from the [LuaJIT project website](http://luajit.org/download.html) and Lua 5.1, from the [Lua project website](http://www.lua.org/). Some distribution package managers also distribute LuaJIT and/or Lua. -1. Download the latest version of the ngx_devel_kit (NDK) module [HERE](https://github.com/simplresty/ngx_devel_kit/tags). -1. Download the latest version of ngx_lua [HERE](https://github.com/openresty/lua-nginx-module/tags). -1. Download the latest version of Nginx [HERE](http://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility)) - -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/ - - # tell nginx's build system where to find LuaJIT 2.0: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.0 - - # tell nginx's build system where to find LuaJIT 2.1: - export LUAJIT_LIB=/path/to/luajit/lib - export LUAJIT_INC=/path/to/luajit/include/luajit-2.1 - - # or tell where to find Lua if using Lua instead: - #export LUA_LIB=/path/to/lua/lib - #export LUA_INC=/path/to/lua/include - - # Here we assume Nginx is to be installed under /opt/nginx/. - ./configure --prefix=/opt/nginx \ - --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ - --add-module=/path/to/ngx_devel_kit \ - --add-module=/path/to/lua-nginx-module - - # Note that you may also want to add `./configure` options which are used in your - # current nginx build. - # You can get usually those options using command nginx -V - - # you can change the parallism number 2 below to fit the number of spare CPU cores in your - # machine. - make -j2 - make install -``` - -[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_lua_module.so; -``` - -[Back to TOC](#table-of-contents) - -C Macro Configurations ----------------------- - -While building this module either via OpenResty or with the NGINX core, you can define the following C macros via the C compiler options: - -* `NGX_LUA_USE_ASSERT` - When defined, will enable assertions in the ngx_lua C code base. Recommended for debugging or testing builds. It can introduce some (small) runtime overhead when enabled. This macro was first introduced in the `v0.9.10` release. -* `NGX_LUA_ABORT_AT_PANIC` - When the Lua/LuaJIT VM panics, ngx_lua will instruct the current nginx worker process to quit gracefully by default. By specifying this C macro, ngx_lua will abort the current nginx worker process (which usually result in a core dump file) immediately. This option is useful for debugging VM panics. This option was first introduced in the `v0.9.8` release. -* `NGX_LUA_NO_FFI_API` - Excludes pure C API functions for FFI-based Lua API for NGINX (as required by [lua-resty-core](https://github.com/openresty/lua-resty-core#readme), for example). Enabling this macro can make the resulting binary code size smaller. - -To enable one or more of these macros, just pass extra C compiler options to the `./configure` script of either NGINX or OpenResty. For instance, - - - ./configure --with-cc-opt="-DNGX_LUA_USE_ASSERT -DNGX_LUA_ABORT_AT_PANIC" - - -[Back to TOC](#table-of-contents) - -Installation on Ubuntu 11.10 ----------------------------- - -Note that it is recommended to use LuaJIT 2.0 or LuaJIT 2.1 instead of the standard Lua 5.1 interpreter wherever possible. - -If the standard Lua 5.1 interpreter is required however, run the following command to install it from the Ubuntu repository: - -```bash - - apt-get install -y lua5.1 liblua5.1-0 liblua5.1-0-dev -``` - -Everything should be installed correctly, except for one small tweak. - -Library name `liblua.so` has been changed in liblua5.1 package, it only comes with `liblua5.1.so`, which needs to be symlinked to `/usr/lib` so it could be found during the configuration process. - -```bash - - ln -s /usr/lib/x86_64-linux-gnu/liblua5.1.so /usr/lib/liblua.so -``` - -[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) - -Code Repository -=============== - -The code repository of this project is hosted on github at [openresty/lua-nginx-module](https://github.com/openresty/lua-nginx-module). - -[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/openresty/lua-nginx-module/issues), -1. or posting to the [OpenResty community](#community). - -[Back to TOC](#table-of-contents) - -Lua/LuaJIT bytecode support -=========================== - -As from the `v0.5.0rc32` release, all `*_by_lua_file` configure directives (such as [content_by_lua_file](#content_by_lua_file)) support loading Lua 5.1 and LuaJIT 2.0/2.1 raw bytecode files directly. - -Please note that the bytecode format used by LuaJIT 2.0/2.1 is not compatible with that used by the standard Lua 5.1 interpreter. So if using LuaJIT 2.0/2.1 with ngx_lua, LuaJIT compatible bytecode files must be generated as shown: - -```bash - - /path/to/luajit/bin/luajit -b /path/to/input_file.lua /path/to/output_file.ljbc -``` - -The `-bg` option can be used to include debug information in the LuaJIT bytecode file: - -```bash - - /path/to/luajit/bin/luajit -bg /path/to/input_file.lua /path/to/output_file.ljbc -``` - -Please refer to the official LuaJIT documentation on the `-b` option for more details: - - - -Also, the bytecode files generated by LuaJIT 2.1 is *not* compatible with LuaJIT 2.0, and vice versa. The support for LuaJIT 2.1 bytecode was first added in ngx_lua v0.9.3. - -Similarly, if using the standard Lua 5.1 interpreter with ngx_lua, Lua compatible bytecode files must be generated using the `luac` commandline utility as shown: - -```bash - - luac -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Unlike as with LuaJIT, debug information is included in standard Lua 5.1 bytecode files by default. This can be striped out by specifying the `-s` option as shown: - -```bash - - luac -s -o /path/to/output_file.luac /path/to/input_file.lua -``` - -Attempts to load standard Lua 5.1 bytecode files into ngx_lua instances linked to LuaJIT 2.0/2.1 or vice versa, will result in an error message, such as that below, being logged into the Nginx `error.log` file: - - - [error] 13909#0: *1 failed to load Lua inlined code: bad byte-code header in /path/to/test_file.luac - - -Loading bytecode files via the Lua primitives like `require` and `dofile` should always work as expected. - -[Back to TOC](#table-of-contents) - -System Environment Variable Support -=================================== - -If you want to access the system environment variable, say, `foo`, in Lua via the standard Lua API [os.getenv](http://www.lua.org/manual/5.1/manual.html#pdf-os.getenv), then you should also list this environment variable name in your `nginx.conf` file via the [env directive](http://nginx.org/en/docs/ngx_core_module.html#env). For example, - -```nginx - - env foo; -``` - -[Back to TOC](#table-of-contents) - -HTTP 1.0 support -================ - -The HTTP 1.0 protocol does not support chunked output and requires an explicit `Content-Length` header when the response body is not empty in order to support the HTTP 1.0 keep-alive. -So when a HTTP 1.0 request is made and the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`, ngx_lua will buffer the -output of [ngx.say](#ngxsay) and [ngx.print](#ngxprint) calls and also postpone sending response headers until all the response body output is received. -At that time ngx_lua can calculate the total length of the body and construct a proper `Content-Length` header to return to the HTTP 1.0 client. -If the `Content-Length` response header is set in the running Lua code, however, this buffering will be disabled even if the [lua_http10_buffering](#lua_http10_buffering) directive is turned `on`. - -For large streaming output responses, it is important to disable the [lua_http10_buffering](#lua_http10_buffering) directive to minimise memory usage. - -Note that common HTTP benchmark tools such as `ab` and `http_load` issue HTTP 1.0 requests by default. -To force `curl` to send HTTP 1.0 requests, use the `-0` option. - -[Back to TOC](#table-of-contents) - -Statically Linking Pure Lua Modules -=================================== - -When LuaJIT 2.x is used, it is possible to statically link the bytecode of pure Lua modules into the Nginx executable. - -Basically you use the `luajit` executable to compile `.lua` Lua module files to `.o` object files containing the exported bytecode data, and then link the `.o` files directly in your Nginx build. - -Below is a trivial example to demonstrate this. Consider that we have the following `.lua` file named `foo.lua`: - -```lua - - -- foo.lua - local _M = {} - - function _M.go() - print("Hello from foo") - end - - return _M -``` - -And then we compile this `.lua` file to `foo.o` file: - - /path/to/luajit/bin/luajit -bg foo.lua foo.o - -What matters here is the name of the `.lua` file, which determines how you use this module later on the Lua land. The file name `foo.o` does not matter at all except the `.o` file extension (which tells `luajit` what output format is used). If you want to strip the Lua debug information from the resulting bytecode, you can just specify the `-b` option above instead of `-bg`. - -Then when building Nginx or OpenResty, pass the `--with-ld-opt="foo.o"` option to the `./configure` script: - -```bash - - ./configure --with-ld-opt="/path/to/foo.o" ... -``` - -Finally, you can just do the following in any Lua code run by ngx_lua: - -```lua - - local foo = require "foo" - foo.go() -``` - -And this piece of code no longer depends on the external `foo.lua` file any more because it has already been compiled into the `nginx` executable. - -If you want to use dot in the Lua module name when calling `require`, as in - -```lua - - local foo = require "resty.foo" -``` - -then you need to rename the `foo.lua` file to `resty_foo.lua` before compiling it down to a `.o` file with the `luajit` command-line utility. - -It is important to use exactly the same version of LuaJIT when compiling `.lua` files to `.o` files as building nginx + ngx_lua. This is because the LuaJIT bytecode format may be incompatible between different LuaJIT versions. When the bytecode format is incompatible, you will see a Lua runtime error saying that the Lua module is not found. - -When you have multiple `.lua` files to compile and link, then just specify their `.o` files at the same time in the value of the `--with-ld-opt` option. For instance, - -```bash - - ./configure --with-ld-opt="/path/to/foo.o /path/to/bar.o" ... -``` - -If you have just too many `.o` files, then it might not be feasible to name them all in a single command. In this case, you can build a static library (or archive) for your `.o` files, as in - -```bash - - ar rcus libmyluafiles.a *.o -``` - -then you can link the `myluafiles` archive as a whole to your nginx executable: - -```bash - - ./configure \ - --with-ld-opt="-L/path/to/lib -Wl,--whole-archive -lmyluafiles -Wl,--no-whole-archive" -``` - -where `/path/to/lib` is the path of the directory containing the `libmyluafiles.a` file. It should be noted that the linker option `--whole-archive` is required here because otherwise our archive will be skipped because no symbols in our archive are mentioned in the main parts of the nginx executable. - -[Back to TOC](#table-of-contents) - -Data Sharing within an Nginx Worker -=================================== - -To globally share data among all the requests handled by the same nginx worker process, encapsulate the shared data into a Lua module, use the Lua `require` builtin to import the module, and then manipulate the shared data in Lua. This works because required Lua modules are loaded only once and all coroutines will share the same copy of the module (both its code and data). Note however that Lua global variables (note, not module-level variables) WILL NOT persist between requests because of the one-coroutine-per-request isolation design. - -Here is a complete small example: - -```lua - - -- mydata.lua - local _M = {} - - local data = { - dog = 3, - cat = 4, - pig = 5, - } - - function _M.get_age(name) - return data[name] - end - - return _M -``` - -and then accessing it from `nginx.conf`: - -```nginx - - location /lua { - content_by_lua_block { - local mydata = require "mydata" - ngx.say(mydata.get_age("dog")) - } - } -``` - -The `mydata` module in this example will only be loaded and run on the first request to the location `/lua`, -and all subsequent requests to the same nginx worker process will use the reloaded instance of the -module as well as the same copy of the data in it, until a `HUP` signal is sent to the Nginx master process to force a reload. -This data sharing technique is essential for high performance Lua applications based on this module. - -Note that this data sharing is on a *per-worker* basis and not on a *per-server* basis. That is, when there are multiple nginx worker processes under an Nginx master, data sharing cannot cross the process boundary between these workers. - -It is usually recommended to share read-only data this way. You can also share changeable data among all the concurrent requests of each nginx worker process as -long as there is *no* nonblocking I/O operations (including [ngx.sleep](#ngxsleep)) -in the middle of your calculations. As long as you do not give the -control back to the nginx event loop and ngx_lua's light thread -scheduler (even implicitly), there can never be any race conditions in -between. For this reason, always be very careful when you want to share changeable data on the -worker level. Buggy optimizations can easily lead to hard-to-debug -race conditions under load. - -If server-wide data sharing is required, then use one or more of the following approaches: - -1. Use the [ngx.shared.DICT](#ngxshareddict) API provided by this module. -1. Use only a single nginx worker and a single server (this is however not recommended when there is a multi core CPU or multiple CPUs in a single machine). -1. Use data storage mechanisms such as `memcached`, `redis`, `MySQL` or `PostgreSQL`. [The OpenResty bundle](http://openresty.org) associated with this module comes with a set of companion Nginx modules and Lua libraries that provide interfaces with these data storage mechanisms. - -[Back to TOC](#table-of-contents) - -Known Issues -============ - -[Back to TOC](#table-of-contents) - -TCP socket connect operation issues ------------------------------------ -The [tcpsock:connect](#tcpsockconnect) method may indicate `success` despite connection failures such as with `Connection Refused` errors. - -However, later attempts to manipulate the cosocket object will fail and return the actual error status message generated by the failed connect operation. - -This issue is due to limitations in the Nginx event model and only appears to affect Mac OS X. - -[Back to TOC](#table-of-contents) - -Lua Coroutine Yielding/Resuming -------------------------------- -* Because Lua's `dofile` and `require` builtins are currently implemented as C functions in both Lua 5.1 and LuaJIT 2.0/2.1, if the Lua file being loaded by `dofile` or `require` invokes [ngx.location.capture*](#ngxlocationcapture), [ngx.exec](#ngxexec), [ngx.exit](#ngxexit), or other API functions requiring yielding in the *top-level* scope of the Lua file, then the Lua error "attempt to yield across C-call boundary" will be raised. To avoid this, put these calls requiring yielding into your own Lua functions in the Lua file instead of the top-level scope of the file. -* As the standard Lua 5.1 interpreter's VM is not fully resumable, the methods [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), [ngx.redirect](#ngxredirect), [ngx.exec](#ngxexec), and [ngx.exit](#ngxexit) cannot be used within the context of a Lua [pcall()](http://www.lua.org/manual/5.1/manual.html#pdf-pcall) or [xpcall()](http://www.lua.org/manual/5.1/manual.html#pdf-xpcall) or even the first line of the `for ... in ...` statement when the standard Lua 5.1 interpreter is used and the `attempt to yield across metamethod/C-call boundary` error will be produced. Please use LuaJIT 2.x, which supports a fully resumable VM, to avoid this. - -[Back to TOC](#table-of-contents) - -Lua Variable Scope ------------------- -Care must be taken when importing modules and this form should be used: - -```lua - - local xxx = require('xxx') -``` - -instead of the old deprecated form: - -```lua - - require('xxx') -``` - -Here is the reason: by design, the global environment has exactly the same lifetime as the Nginx request handler associated with it. Each request handler has its own set of Lua global variables and that is the idea of request isolation. The Lua module is actually loaded by the first Nginx request handler and is cached by the `require()` built-in in the `package.loaded` table for later reference, and the `module()` builtin used by some Lua modules has the side effect of setting a global variable to the loaded module table. But this global variable will be cleared at the end of the request handler, and every subsequent request handler all has its own (clean) global environment. So one will get Lua exception for accessing the `nil` value. - -The use of Lua global variables is a generally inadvisable in the ngx_lua context as: - -1. the misuse of Lua globals has detrimental side effects on concurrent requests when such variables should instead be local in scope, -1. Lua global variables require Lua table look-ups in the global environment which is computationally expensive, and -1. some Lua global variable references may include typing errors which make such difficult to debug. - -It is therefore *highly* recommended to always declare such within an appropriate local scope instead. - -```lua - - -- Avoid - foo = 123 - -- Recommended - local foo = 123 - - -- Avoid - function foo() return 123 end - -- Recommended - local function foo() return 123 end -``` - - -To find all instances of Lua global variables in your Lua code, run the [lua-releng tool](https://github.com/openresty/nginx-devel-utils/blob/master/lua-releng) across all `.lua` source files: - - $ lua-releng - Checking use of Lua global variables in file lib/foo/bar.lua ... - 1 [1489] SETGLOBAL 7 -1 ; contains - 55 [1506] GETGLOBAL 7 -3 ; setvar - 3 [1545] GETGLOBAL 3 -4 ; varexpand - -The output says that the line 1489 of file `lib/foo/bar.lua` writes to a global variable named `contains`, the line 1506 reads from the global variable `setvar`, and line 1545 reads the global `varexpand`. - -This tool will guarantee that local variables in the Lua module functions are all declared with the `local` keyword, otherwise a runtime exception will be thrown. It prevents undesirable race conditions while accessing such variables. See [Data Sharing within an Nginx Worker](#data-sharing-within-an-nginx-worker) for the reasons behind this. - -[Back to TOC](#table-of-contents) - -Locations Configured by Subrequest Directives of Other Modules --------------------------------------------------------------- -The [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) directives cannot capture locations that include the [add_before_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_before_body), [add_after_body](http://nginx.org/en/docs/http/ngx_http_addition_module.html#add_after_body), [auth_request](http://nginx.org/en/docs/http/ngx_http_auth_request_module.html#auth_request), [echo_location](http://github.com/openresty/echo-nginx-module#echo_location), [echo_location_async](http://github.com/openresty/echo-nginx-module#echo_location_async), [echo_subrequest](http://github.com/openresty/echo-nginx-module#echo_subrequest), or [echo_subrequest_async](http://github.com/openresty/echo-nginx-module#echo_subrequest_async) directives. - -```nginx - - location /foo { - content_by_lua_block { - res = ngx.location.capture("/bar") - } - } - location /bar { - echo_location /blah; - } - location /blah { - echo "Success!"; - } -``` - -```nginx - - $ curl -i http://example.com/foo -``` - -will not work as expected. - -[Back to TOC](#table-of-contents) - -Cosockets Not Available Everywhere ----------------------------------- - -Due to internal limitations in the nginx core, the cosocket API is disabled in the following contexts: [set_by_lua*](#set_by_lua), [log_by_lua*](#log_by_lua), [header_filter_by_lua*](#header_filter_by_lua), and [body_filter_by_lua](#body_filter_by_lua). - -The cosockets are currently also disabled in the [init_by_lua*](#init_by_lua) and [init_worker_by_lua*](#init_worker_by_lua) directive contexts but we may add support for these contexts in the future because there is no limitation in the nginx core (or the limitation might be worked around). - -There exists a work-around, however, when the original context does *not* need to wait for the cosocket results. That is, creating a zero-delay timer via the [ngx.timer.at](#ngxtimerat) API and do the cosocket results in the timer handler, which runs asynchronously as to the original context creating the timer. - -[Back to TOC](#table-of-contents) - -Special Escaping Sequences --------------------------- - -**NOTE** Following the `v0.9.17` release, this pitfall can be avoided by using the `*_by_lua_block {}` configuration directives. - -PCRE sequences such as `\d`, `\s`, or `\w`, require special attention because in string literals, the backslash character, `\`, is stripped out by both the Lua language parser and by the nginx config file parser before processing if not within a `*_by_lua_block {}` directive. So the following snippet will not work as expected: - -```nginx - - # nginx.conf - ? location /test { - ? content_by_lua ' - ? local regex = "\d+" -- THIS IS WRONG OUTSIDE OF A *_by_lua_block DIRECTIVE - ? local m = ngx.re.match("hello, 1234", regex) - ? if m then ngx.say(m[0]) else ngx.say("not matched!") end - ? '; - ? } - # evaluates to "not matched!" -``` - -To avoid this, *double* escape the backslash: - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = "\\\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -Here, `\\\\d+` is stripped down to `\\d+` by the Nginx config file parser and this is further stripped down to `\d+` by the Lua language parser before running. - -Alternatively, the regex pattern can be presented as a long-bracketed Lua string literal by encasing it in "long brackets", `[[...]]`, in which case backslashes have to only be escaped once for the Nginx config file parser. - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = [[\\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -Here, `[[\\d+]]` is stripped down to `[[\d+]]` by the Nginx config file parser and this is processed correctly. - -Note that a longer from of the long bracket, `[=[...]=]`, may be required if the regex pattern contains `[...]` sequences. -The `[=[...]=]` form may be used as the default form if desired. - -```nginx - - # nginx.conf - location /test { - content_by_lua ' - local regex = [=[[0-9]+]=] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - '; - } - # evaluates to "1234" -``` - -An alternative approach to escaping PCRE sequences is to ensure that Lua code is placed in external script files and executed using the various `*_by_lua_file` directives. -With this approach, the backslashes are only stripped by the Lua language parser and therefore only need to be escaped once each. - -```lua - - -- test.lua - local regex = "\\d+" - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - -- evaluates to "1234" -``` - -Within external script files, PCRE sequences presented as long-bracketed Lua string literals do not require modification. - -```lua - - -- test.lua - local regex = [[\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - -- evaluates to "1234" -``` - -As noted earlier, PCRE sequences presented within `*_by_lua_block {}` directives (available following the `v0.9.17` release) do not require modification. - -```nginx - - # nginx.conf - location /test { - content_by_lua_block { - local regex = [[\d+]] - local m = ngx.re.match("hello, 1234", regex) - if m then ngx.say(m[0]) else ngx.say("not matched!") end - } - } - # evaluates to "1234" -``` - - -[Back to TOC](#table-of-contents) - -Mixing with SSI Not Supported ------------------------------ - -Mixing SSI with ngx_lua in the same Nginx request is not supported at all. Just use ngx_lua exclusively. Everything you can do with SSI can be done atop ngx_lua anyway and it can be more efficient when using ngx_lua. - -[Back to TOC](#table-of-contents) - -SPDY Mode Not Fully Supported ------------------------------ - -Certain Lua APIs provided by ngx_lua do not work in Nginx's SPDY mode yet: [ngx.location.capture](#ngxlocationcapture), [ngx.location.capture_multi](#ngxlocationcapture_multi), and [ngx.req.socket](#ngxreqsocket). - -[Back to TOC](#table-of-contents) - -Missing data on short circuited requests ----------------------------------------- - -Nginx may terminate a request early with (at least): - -* 400 (Bad Request) -* 405 (Not Allowed) -* 408 (Request Timeout) -* 413 (Request Entity Too Large) -* 414 (Request URI Too Large) -* 494 (Request Headers Too Large) -* 499 (Client Closed Request) -* 500 (Internal Server Error) -* 501 (Not Implemented) - -This means that phases that normally run are skipped, such as the rewrite or -access phase. This also means that later phases that are run regardless, e.g. -[log_by_lua](#log_by_lua), will not have access to information that is normally set in those -phases. - -[Back to TOC](#table-of-contents) - -TODO -==== - -* cosocket: implement LuaSocket's unconnected UDP API. -* port this module to the "datagram" subsystem of NGINX for implementing general UDP servers instead of HTTP -servers in Lua. For example, -```lua - - datagram { - server { - listen 1953; - handler_by_lua_block { - -- custom Lua code implementing the special UDP server... - } - } - } -``` -* shm: implement a "shared queue API" to complement the existing [shared dict](#lua_shared_dict) API. -* cosocket: add support in the context of [init_by_lua*](#init_by_lua). -* cosocket: implement the `bind()` method for stream-typed cosockets. -* cosocket: pool-based backend concurrency level control: implement automatic `connect` queueing when the backend concurrency exceeds its connection pool limit. -* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method. -* add new API function `ngx.resp.add_header` to emulate the standard `add_header` config directive. -* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option -* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), [ngx.header.HEADER](#ngxheaderheader), and etc. -* add configure options for different strategies of handling the cosocket connection exceeding in the pools. -* add directives to run Lua codes when nginx stops. -* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side. -* add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks. -* add `stat` mode similar to [mod_lua](https://httpd.apache.org/docs/trunk/mod/mod_lua.html). -* cosocket: add client SSL certificate support. - -[Back to TOC](#table-of-contents) - -Changes -======= - -The changes made in every release of this module are listed in the change logs of the OpenResty bundle: - - - -[Back to TOC](#table-of-contents) - -Test Suite -========== - -The following dependencies are required to run the test suite: - -* Nginx version >= 1.4.2 - -* Perl modules: - * Test::Nginx: - -* Nginx modules: - * [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) - * [ngx_set_misc](https://github.com/openresty/set-misc-nginx-module) - * [ngx_auth_request](http://mdounin.ru/files/ngx_http_auth_request_module-0.2.tar.gz) (this is not needed if you're using Nginx 1.5.4+. - * [ngx_echo](https://github.com/openresty/echo-nginx-module) - * [ngx_memc](https://github.com/openresty/memc-nginx-module) - * [ngx_srcache](https://github.com/openresty/srcache-nginx-module) - * ngx_lua (i.e., this module) - * [ngx_lua_upstream](https://github.com/openresty/lua-upstream-nginx-module) - * [ngx_headers_more](https://github.com/openresty/headers-more-nginx-module) - * [ngx_drizzle](https://github.com/openresty/drizzle-nginx-module) - * [ngx_rds_json](https://github.com/openresty/rds-json-nginx-module) - * [ngx_coolkit](https://github.com/FRiCKLE/ngx_coolkit) - * [ngx_redis2](https://github.com/openresty/redis2-nginx-module) - -The order in which these modules are added during configuration is important because the position of any filter module in the -filtering chain determines the final output, for example. The correct adding order is shown above. - -* 3rd-party Lua libraries: - * [lua-cjson](http://www.kyne.com.au/~mark/software/lua-cjson.php) - -* Applications: - * mysql: create database 'ngx_test', grant all privileges to user 'ngx_test', password is 'ngx_test' - * memcached: listening on the default port, 11211. - * redis: listening on the default port, 6379. - -See also the [developer build script](https://github.com/openresty/lua-nginx-module/blob/master/util/build.sh) for more details on setting up the testing environment. - -To run the whole test suite in the default testing mode: - - cd /path/to/lua-nginx-module - export PATH=/path/to/your/nginx/sbin:$PATH - prove -I/path/to/test-nginx/lib -r t - - -To run specific test files: - - cd /path/to/lua-nginx-module - export PATH=/path/to/your/nginx/sbin:$PATH - prove -I/path/to/test-nginx/lib t/002-content.t t/003-errors.t - - -To run a specific test block in a particular test file, add the line `--- ONLY` to the test block you want to run, and then use the `prove` utility to run that `.t` file. - -There are also various testing modes based on mockeagain, valgrind, and etc. Refer to the [Test::Nginx documentation](http://search.cpan.org/perldoc?Test::Nginx) for more details for various advanced testing modes. See also the test reports for the Nginx test cluster running on Amazon EC2: . - -[Back to TOC](#table-of-contents) - -Copyright and License -===================== - -This module is licensed under the BSD license. - -Copyright (C) 2009-2017, by Xiaozhe Wang (chaoslawful) . - -Copyright (C) 2009-2018, by Yichun "agentzh" Zhang (章亦春) , OpenResty 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: - -* 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 -======== - -* [ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module#readme) for an official port of this module for the NGINX "stream" subsystem (doing generic downstream TCP communications). -* [lua-resty-memcached](https://github.com/openresty/lua-resty-memcached) library based on ngx_lua cosocket. -* [lua-resty-redis](https://github.com/openresty/lua-resty-redis) library based on ngx_lua cosocket. -* [lua-resty-mysql](https://github.com/openresty/lua-resty-mysql) library based on ngx_lua cosocket. -* [lua-resty-upload](https://github.com/openresty/lua-resty-upload) library based on ngx_lua cosocket. -* [lua-resty-dns](https://github.com/openresty/lua-resty-dns) library based on ngx_lua cosocket. -* [lua-resty-websocket](https://github.com/openresty/lua-resty-websocket) library for both WebSocket server and client, based on ngx_lua cosocket. -* [lua-resty-string](https://github.com/openresty/lua-resty-string) library based on [LuaJIT FFI](http://luajit.org/ext_ffi.html). -* [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library for a nonblocking simple lock API. -* [lua-resty-cookie](https://github.com/cloudflare/lua-resty-cookie) library for HTTP cookie manipulation. -* [Routing requests to different MySQL queries based on URI arguments](http://openresty.org/#RoutingMySQLQueriesBasedOnURIArgs) -* [Dynamic Routing Based on Redis and Lua](http://openresty.org/#DynamicRoutingBasedOnRedis) -* [Using LuaRocks with ngx_lua](http://openresty.org/#UsingLuaRocks) -* [Introduction to ngx_lua](https://github.com/openresty/lua-nginx-module/wiki/Introduction) -* [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) -* [echo-nginx-module](http://github.com/openresty/echo-nginx-module) -* [drizzle-nginx-module](http://github.com/openresty/drizzle-nginx-module) -* [postgres-nginx-module](https://github.com/FRiCKLE/ngx_postgres) -* [memc-nginx-module](http://github.com/openresty/memc-nginx-module) -* [The OpenResty bundle](http://openresty.org) -* [Nginx Systemtap Toolkit](https://github.com/openresty/nginx-systemtap-toolkit) - -[Back to TOC](#table-of-contents) - -Directives -========== - -* [lua_capture_error_log](#lua_capture_error_log) -* [lua_use_default_type](#lua_use_default_type) -* [lua_malloc_trim](#lua_malloc_trim) -* [lua_code_cache](#lua_code_cache) -* [lua_regex_cache_max_entries](#lua_regex_cache_max_entries) -* [lua_regex_match_limit](#lua_regex_match_limit) -* [lua_package_path](#lua_package_path) -* [lua_package_cpath](#lua_package_cpath) -* [init_by_lua](#init_by_lua) -* [init_by_lua_block](#init_by_lua_block) -* [init_by_lua_file](#init_by_lua_file) -* [init_worker_by_lua](#init_worker_by_lua) -* [init_worker_by_lua_block](#init_worker_by_lua_block) -* [init_worker_by_lua_file](#init_worker_by_lua_file) -* [set_by_lua](#set_by_lua) -* [set_by_lua_block](#set_by_lua_block) -* [set_by_lua_file](#set_by_lua_file) -* [content_by_lua](#content_by_lua) -* [content_by_lua_block](#content_by_lua_block) -* [content_by_lua_file](#content_by_lua_file) -* [rewrite_by_lua](#rewrite_by_lua) -* [rewrite_by_lua_block](#rewrite_by_lua_block) -* [rewrite_by_lua_file](#rewrite_by_lua_file) -* [access_by_lua](#access_by_lua) -* [access_by_lua_block](#access_by_lua_block) -* [access_by_lua_file](#access_by_lua_file) -* [header_filter_by_lua](#header_filter_by_lua) -* [header_filter_by_lua_block](#header_filter_by_lua_block) -* [header_filter_by_lua_file](#header_filter_by_lua_file) -* [body_filter_by_lua](#body_filter_by_lua) -* [body_filter_by_lua_block](#body_filter_by_lua_block) -* [body_filter_by_lua_file](#body_filter_by_lua_file) -* [log_by_lua](#log_by_lua) -* [log_by_lua_block](#log_by_lua_block) -* [log_by_lua_file](#log_by_lua_file) -* [balancer_by_lua_block](#balancer_by_lua_block) -* [balancer_by_lua_file](#balancer_by_lua_file) -* [lua_need_request_body](#lua_need_request_body) -* [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block) -* [ssl_certificate_by_lua_file](#ssl_certificate_by_lua_file) -* [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block) -* [ssl_session_fetch_by_lua_file](#ssl_session_fetch_by_lua_file) -* [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block) -* [ssl_session_store_by_lua_file](#ssl_session_store_by_lua_file) -* [lua_shared_dict](#lua_shared_dict) -* [lua_socket_connect_timeout](#lua_socket_connect_timeout) -* [lua_socket_send_timeout](#lua_socket_send_timeout) -* [lua_socket_send_lowat](#lua_socket_send_lowat) -* [lua_socket_read_timeout](#lua_socket_read_timeout) -* [lua_socket_buffer_size](#lua_socket_buffer_size) -* [lua_socket_pool_size](#lua_socket_pool_size) -* [lua_socket_keepalive_timeout](#lua_socket_keepalive_timeout) -* [lua_socket_log_errors](#lua_socket_log_errors) -* [lua_ssl_ciphers](#lua_ssl_ciphers) -* [lua_ssl_crl](#lua_ssl_crl) -* [lua_ssl_protocols](#lua_ssl_protocols) -* [lua_ssl_trusted_certificate](#lua_ssl_trusted_certificate) -* [lua_ssl_verify_depth](#lua_ssl_verify_depth) -* [lua_http10_buffering](#lua_http10_buffering) -* [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) -* [access_by_lua_no_postpone](#access_by_lua_no_postpone) -* [lua_transform_underscores_in_response_headers](#lua_transform_underscores_in_response_headers) -* [lua_check_client_abort](#lua_check_client_abort) -* [lua_max_pending_timers](#lua_max_pending_timers) -* [lua_max_running_timers](#lua_max_running_timers) - - -The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and -how the result will be used. Below is a diagram showing the order in which directives are executed. - -![Lua Nginx Modules Directives](https://cloud.githubusercontent.com/assets/2137369/15272097/77d1c09e-1a37-11e6-97ef-d9767035fc3e.png) - -[Back to TOC](#table-of-contents) - -lua_capture_error_log ---------------------- -**syntax:** *lua_capture_error_log size* - -**default:** *none* - -**context:** *http* - -Enables a buffer of the specified `size` for capturing all the nginx error log message data (not just those produced -by this module or the nginx http subsystem, but everything) without touching files or disks. - -You can use units like `k` and `m` in the `size` value, as in - -```nginx - - lua_capture_error_log 100k; -``` - -As a rule of thumb, a 4KB buffer can usually hold about 20 typical error log messages. So do the maths! - -This buffer never grows. If it is full, new error log messages will replace the oldest ones in the buffer. - -The size of the buffer must be bigger than the maximum length of a single error log message (which is 4K in OpenResty and 2K in stock NGINX). - -You can read the messages in the buffer on the Lua land via the -[get_logs()](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#get_logs) -function of the -[ngx.errlog](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) -module of the [lua-resty-core](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#readme) -library. This Lua API function will return the captured error log messages and -also remove these already read from the global capturing buffer, making room -for any new error log data. For this reason, the user should not configure this -buffer to be too big if the user read the buffered error log data fast enough. - -Note that the log level specified in the standard [error_log](http://nginx.org/r/error_log) directive -*does* have effect on this capturing facility. It only captures log -messages of a level no lower than the specified log level in the [error_log](http://nginx.org/r/error_log) directive. -The user can still choose to set an even higher filtering log level on the fly via the Lua API function -[errlog.set_filter_level](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/errlog.md#set_filter_level). -So it is more flexible than the static [error_log](http://nginx.org/r/error_log) directive. - -It is worth noting that there is no way to capture the debugging logs -without building OpenResty or NGINX with the `./configure` -option `--with-debug`. And enabling debugging logs is -strongly discouraged in production builds due to high overhead. - -This directive was first introduced in the `v0.10.9` release. - -[Back to TOC](#directives) - -lua_use_default_type --------------------- -**syntax:** *lua_use_default_type on | off* - -**default:** *lua_use_default_type on* - -**context:** *http, server, location, location if* - -Specifies whether to use the MIME type specified by the [default_type](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) directive for the default value of the `Content-Type` response header. Deactivate this directive if a default `Content-Type` response header for Lua request handlers is not desired. - -This directive is turned on by default. - -This directive was first introduced in the `v0.9.1` release. - -[Back to TOC](#directives) - -lua_malloc_trim ---------------- -**syntax:** *lua_malloc_trim <request-count>* - -**default:** *lua_malloc_trim 1000* - -**context:** *http* - -Asks the underlying `libc` runtime library to release its cached free memory back to the operating system every -`N` requests processed by the NGINX core. By default, `N` is 1000. You can configure the request count -by using your own numbers. Smaller numbers mean more frequent releases, which may introduce higher CPU time consumption and -smaller memory footprint while larger numbers usually lead to less CPU time overhead and relatively larger memory footprint. -Just tune the number for your own use cases. - -Configuring the argument to `0` essentially turns off the periodical memory trimming altogether. - -```nginx - - lua_malloc_trim 0; # turn off trimming completely -``` - -The current implementation uses an NGINX log phase handler to do the request counting. So the appearance of the -[log_subrequest on](http://nginx.org/en/docs/http/ngx_http_core_module.html#log_subrequest) directives in `nginx.conf` -may make the counting faster when subrequests are involved. By default, only "main requests" count. - -Note that this directive does *not* affect the memory allocated by LuaJIT's own allocator based on the `mmap` -system call. - -This directive was first introduced in the `v0.10.7` release. - -[Back to TOC](#directives) - -lua_code_cache --------------- -**syntax:** *lua_code_cache on | off* - -**default:** *lua_code_cache on* - -**context:** *http, server, location, location if* - -Enables or disables the Lua code cache for Lua code in `*_by_lua_file` directives (like [set_by_lua_file](#set_by_lua_file) and -[content_by_lua_file](#content_by_lua_file)) and Lua modules. - -When turning off, every request served by ngx_lua will run in a separate Lua VM instance, starting from the `0.9.3` release. So the Lua files referenced in [set_by_lua_file](#set_by_lua_file), -[content_by_lua_file](#content_by_lua_file), [access_by_lua_file](#access_by_lua_file), -and etc will not be cached -and all Lua modules used will be loaded from scratch. With this in place, developers can adopt an edit-and-refresh approach. - -Please note however, that Lua code written inlined within nginx.conf -such as those specified by [set_by_lua](#set_by_lua), [content_by_lua](#content_by_lua), -[access_by_lua](#access_by_lua), and [rewrite_by_lua](#rewrite_by_lua) will not be updated when you edit the inlined Lua code in your `nginx.conf` file because only the Nginx config file parser can correctly parse the `nginx.conf` -file and the only way is to reload the config file -by sending a `HUP` signal or just to restart Nginx. - -Even when the code cache is enabled, Lua files which are loaded by `dofile` or `loadfile` -in *_by_lua_file cannot be cached (unless you cache the results yourself). Usually you can either use the [init_by_lua](#init_by_lua) -or [init_by_lua_file](#init-by_lua_file) directives to load all such files or just make these Lua files true Lua modules -and load them via `require`. - -The ngx_lua module does not support the `stat` mode available with the -Apache `mod_lua` module (yet). - -Disabling the Lua code cache is strongly -discouraged for production use and should only be used during -development as it has a significant negative impact on overall performance. For example, the performance of a "hello world" Lua example can drop by an order of magnitude after disabling the Lua code cache. - -[Back to TOC](#directives) - -lua_regex_cache_max_entries ---------------------------- -**syntax:** *lua_regex_cache_max_entries <num>* - -**default:** *lua_regex_cache_max_entries 1024* - -**context:** *http* - -Specifies the maximum number of entries allowed in the worker process level compiled regex cache. - -The regular expressions used in [ngx.re.match](#ngxrematch), [ngx.re.gmatch](#ngxregmatch), [ngx.re.sub](#ngxresub), and [ngx.re.gsub](#ngxregsub) will be cached within this cache if the regex option `o` (i.e., compile-once flag) is specified. - -The default number of entries allowed is 1024 and when this limit is reached, new regular expressions will not be cached (as if the `o` option was not specified) and there will be one, and only one, warning in the `error.log` file: - - - 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... - - -If you are using the `ngx.re.*` implementation of [lua-resty-core](https://github.com/openresty/lua-resty-core) by loading the `resty.core.regex` module (or just the `resty.core` module), then an LRU cache is used for the regex cache being used here. - -Do not activate the `o` option for regular expressions (and/or `replace` string arguments for [ngx.re.sub](#ngxresub) and [ngx.re.gsub](#ngxregsub)) that are generated *on the fly* and give rise to infinite variations to avoid hitting the specified limit. - -[Back to TOC](#directives) - -lua_regex_match_limit ---------------------- -**syntax:** *lua_regex_match_limit <num>* - -**default:** *lua_regex_match_limit 0* - -**context:** *http* - -Specifies the "match limit" used by the PCRE library when executing the [ngx.re API](#ngxrematch). To quote the PCRE manpage, "the limit ... has the effect of limiting the amount of backtracking that can take place." - -When the limit is hit, the error string "pcre_exec() failed: -8" will be returned by the [ngx.re API](#ngxrematch) functions on the Lua land. - -When setting the limit to 0, the default "match limit" when compiling the PCRE library is used. And this is the default value of this directive. - -This directive was first introduced in the `v0.8.5` release. - -[Back to TOC](#directives) - -lua_package_path ----------------- - -**syntax:** *lua_package_path <lua-style-path-str>* - -**default:** *The content of LUA_PATH environment variable or Lua's compiled-in defaults.* - -**context:** *http* - -Sets the Lua module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The path string is in standard Lua path form, and `;;` -can be used to stand for the original search paths. - -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. - -[Back to TOC](#directives) - -lua_package_cpath ------------------ - -**syntax:** *lua_package_cpath <lua-style-cpath-str>* - -**default:** *The content of LUA_CPATH environment variable or Lua's compiled-in defaults.* - -**context:** *http* - -Sets the Lua C-module search path used by scripts specified by [set_by_lua](#set_by_lua), -[content_by_lua](#content_by_lua) and others. The cpath string is in standard Lua cpath form, and `;;` -can be used to stand for the original cpath. - -As from the `v0.5.0rc29` release, the special notation `$prefix` or `${prefix}` can be used in the search path string to indicate the path of the `server prefix` usually determined by the `-p PATH` command-line option while starting the Nginx server. - -[Back to TOC](#directives) - -init_by_lua ------------ - -**syntax:** *init_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *loading-config* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_by_lua_block](#init_by_lua_block) directive instead. - -Runs the Lua code specified by the argument `` on the global Lua VM level when the Nginx master process (if any) is loading the Nginx config file. - -When Nginx receives the `HUP` signal and starts reloading the config file, the Lua VM will also be re-created and `init_by_lua` will run again on the new Lua VM. In case that the [lua_code_cache](#lua_code_cache) directive is turned off (default on), the `init_by_lua` handler will run upon every request because in this special mode a standalone Lua VM is always created for each request. - -Usually you can pre-load Lua modules at server start-up by means of this hook and take advantage of modern operating systems' copy-on-write (COW) optimization. Here is an example for pre-loading Lua modules: - -```nginx - - # this runs before forking out nginx worker processes: - init_by_lua_block { require "cjson" } - - server { - location = /api { - content_by_lua_block { - -- the following require() will just return - -- the alrady loaded module from package.loaded: - ngx.say(require "cjson".encode{dog = 5, cat = 6}) - } - } - } -``` - -You can also initialize the [lua_shared_dict](#lua_shared_dict) shm storage at this phase. Here is an example for this: - -```nginx - - lua_shared_dict dogs 1m; - - init_by_lua_block { - local dogs = ngx.shared.dogs; - dogs:set("Tom", 56) - } - - server { - location = /api { - content_by_lua_block { - local dogs = ngx.shared.dogs; - ngx.say(dogs:get("Tom")) - } - } - } -``` - -But note that, the [lua_shared_dict](#lua_shared_dict)'s shm storage will not be cleared through a config reload (via the `HUP` signal, for example). So if you do *not* want to re-initialize the shm storage in your `init_by_lua` code in this case, then you just need to set a custom flag in the shm storage and always check the flag in your `init_by_lua` code. - -Because the Lua code in this context runs before Nginx forks its worker processes (if any), data or code loaded here will enjoy the [Copy-on-write (COW)](http://en.wikipedia.org/wiki/Copy-on-write) feature provided by many operating systems among all the worker processes, thus saving a lot of memory. - -Do *not* initialize your own Lua global variables in this context because use of Lua global variables have performance penalties and can lead to global namespace pollution (see the [Lua Variable Scope](#lua-variable-scope) section for more details). The recommended way is to use proper [Lua module](http://www.lua.org/manual/5.1/manual.html#5.3) files (but do not use the standard Lua function [module()](http://www.lua.org/manual/5.1/manual.html#pdf-module) to define Lua modules because it pollutes the global namespace as well) and call [require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) to load your own module files in `init_by_lua` or other contexts ([require()](http://www.lua.org/manual/5.1/manual.html#pdf-require) does cache the loaded Lua modules in the global `package.loaded` table in the Lua registry so your modules will only loaded once for the whole Lua VM instance). - -Only a small set of the [Nginx API for Lua](#nginx-api-for-lua) is supported in this context: - -* Logging APIs: [ngx.log](#ngxlog) and [print](#print), -* Shared Dictionary API: [ngx.shared.DICT](#ngxshareddict). - -More Nginx APIs for Lua may be supported in this context upon future user requests. - -Basically you can safely use Lua libraries that do blocking I/O in this very context because blocking the master process during server start-up is completely okay. Even the Nginx core does blocking I/O (at least on resolving upstream's host names) at the configure-loading phase. - -You should be very careful about potential security vulnerabilities in your Lua code registered in this context because the Nginx master process is often run under the `root` account. - -This directive was first introduced in the `v0.5.5` release. - -[Back to TOC](#directives) - -init_by_lua_block ------------------ - -**syntax:** *init_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *loading-config* - -Similar to the [init_by_lua](#init_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - init_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -init_by_lua_file ----------------- - -**syntax:** *init_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *loading-config* - -Equivalent to [init_by_lua](#init_by_lua), except that the file specified by `` contains the Lua code or [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.5` release. - -[Back to TOC](#directives) - -init_worker_by_lua ------------------- - -**syntax:** *init_worker_by_lua <lua-script-str>* - -**context:** *http* - -**phase:** *starting-worker* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [init_worker_by_lua_block](#init_worker_by_lua_block) directive instead. - -Runs the specified Lua code upon every Nginx worker process's startup when the master process is enabled. When the master process is disabled, this hook will just run after [init_by_lua*](#init_by_lua). - -This hook is often used to create per-worker reoccurring timers (via the [ngx.timer.at](#ngxtimerat) Lua API), either for backend health-check or other timed routine work. Below is an example, - -```nginx - - init_worker_by_lua ' - local delay = 3 -- in seconds - local new_timer = ngx.timer.at - local log = ngx.log - local ERR = ngx.ERR - local check - - check = function(premature) - if not premature then - -- do the health check or other routine work - local ok, err = new_timer(delay, check) - if not ok then - log(ERR, "failed to create timer: ", err) - return - end - end - end - - local hdl, err = new_timer(delay, check) - if not hdl then - log(ERR, "failed to create timer: ", err) - return - end - '; -``` - -This directive was first introduced in the `v0.9.5` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -init_worker_by_lua_block ------------------------- - -**syntax:** *init_worker_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *starting-worker* - -Similar to the [init_worker_by_lua](#init_worker_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - init_worker_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -init_worker_by_lua_file ------------------------ - -**syntax:** *init_worker_by_lua_file <lua-file-path>* - -**context:** *http* - -**phase:** *starting-worker* - -Similar to [init_worker_by_lua](#init_worker_by_lua), but accepts the file path to a Lua source file or Lua bytecode file. - -This directive was first introduced in the `v0.9.5` release. - -This hook no longer runs in the cache manager and cache loader processes since the `v0.10.12` release. - -[Back to TOC](#directives) - -set_by_lua ----------- - -**syntax:** *set_by_lua $res <lua-script-str> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [set_by_lua_block](#set_by_lua_block) directive instead. - -Executes code specified in `` with optional input arguments `$arg1 $arg2 ...`, and returns string output to `$res`. -The code in `` can make [API calls](#nginx-api-for-lua) and can retrieve input arguments from the `ngx.arg` table (index starts from `1` and increases sequentially). - -This directive is designed to execute short, fast running code blocks as the Nginx event loop is blocked during code execution. Time consuming code sequences should therefore be avoided. - -This directive is implemented by injecting custom commands into the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s command list. Because [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) does not support nonblocking I/O in its commands, Lua APIs requiring yielding the current Lua "light thread" cannot work in this directive. - -At least the following API functions are currently disabled within the context of `set_by_lua`: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). -* Sleeping API function [ngx.sleep](#ngxsleep). - -In addition, note that this directive can only write out a value to a single Nginx variable at -a time. However, a workaround is possible using the [ngx.var.VARIABLE](#ngxvarvariable) interface. - -```nginx - - location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally - '; - - echo "sum = $sum, diff = $diff"; - } -``` - -This directive can be freely mixed with all directives of the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html), [set-misc-nginx-module](http://github.com/openresty/set-misc-nginx-module), and [array-var-nginx-module](http://github.com/openresty/array-var-nginx-module) modules. All of these directives will run in the same order as they appear in the config file. - -```nginx - - set $foo 32; - set_by_lua $bar 'return tonumber(ngx.var.foo) + 1'; - set $baz "bar: $bar"; # $baz == "bar: 33" -``` - -As from the `v0.5.0rc29` release, Nginx variable interpolation is disabled in the `` argument of this directive and therefore, the dollar sign character (`$`) can be used directly. - -This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) module. - -[Back to TOC](#directives) - -set_by_lua_block ----------------- - -**syntax:** *set_by_lua_block $res { lua-script }* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -Similar to the [set_by_lua](#set_by_lua) directive except that - -1. this directive inlines the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping), and -1. this directive does not support extra arguments after the Lua script as in [set_by_lua](#set_by_lua). - -For example, - -```nginx - - set_by_lua_block $res { return 32 + math.cos(32) } - # $res now has the value "32.834223360507" or alike. -``` - -No special escaping is required in the Lua code block. - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -set_by_lua_file ---------------- -**syntax:** *set_by_lua_file $res <path-to-lua-script-file> [$arg1 $arg2 ...]* - -**context:** *server, server if, location, location if* - -**phase:** *rewrite* - -Equivalent to [set_by_lua](#set_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variable interpolation is supported in the `` argument string of this directive. But special care must be taken for injection attacks. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -This directive requires the [ngx_devel_kit](https://github.com/simplresty/ngx_devel_kit) module. - -[Back to TOC](#directives) - -content_by_lua --------------- - -**syntax:** *content_by_lua <lua-script-str>* - -**context:** *location, location if* - -**phase:** *content* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [content_by_lua_block](#content_by_lua_block) directive instead. - -Acts as a "content handler" and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Do not use this directive and other content handler directives in the same location. For example, this directive and the [proxy_pass](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) directive should not be used in the same location. - -[Back to TOC](#directives) - -content_by_lua_block --------------------- - -**syntax:** *content_by_lua_block { lua-script }* - -**context:** *location, location if* - -**phase:** *content* - -Similar to the [content_by_lua](#content_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - content_by_lua_block { - ngx.say("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -content_by_lua_file -------------------- - -**syntax:** *content_by_lua_file <path-to-lua-script-file>* - -**context:** *location, location if* - -**phase:** *content* - -Equivalent to [content_by_lua](#content_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by -switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -Nginx variables are supported in the file path for dynamic dispatch, for example: - -```nginx - - # CAUTION: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/([-_a-zA-Z0-9/]+) { - set $path $1; - content_by_lua_file /path/to/lua/app/root/$path.lua; - } -``` - -But be very careful about malicious user inputs and always carefully validate or filter out the user-supplied path components. - -[Back to TOC](#directives) - -rewrite_by_lua --------------- - -**syntax:** *rewrite_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [rewrite_by_lua_block](#rewrite_by_lua_block) directive instead. - -Acts as a rewrite phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Note that this handler always runs *after* the standard [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html). So the following will work as expected: - -```nginx - - location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; - } -``` - -because `set $a 12` and `set $b ""` run *before* [rewrite_by_lua](#rewrite_by_lua). - -On the other hand, the following will not work as expected: - -```nginx - - ? location /foo { - ? set $a 12; # create and initialize $a - ? set $b ''; # create and initialize $b - ? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - ? if ($b = '13') { - ? rewrite ^ /bar redirect; - ? break; - ? } - ? - ? echo "res = $b"; - ? } -``` - -because `if` runs *before* [rewrite_by_lua](#rewrite_by_lua) even if it is placed after [rewrite_by_lua](#rewrite_by_lua) in the config. - -The right way of doing this is as follows: - -```nginx - - location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; - } -``` - -Note that the [ngx_eval](http://www.grid.net.ru/nginx/eval.en.html) module can be approximated by using [rewrite_by_lua](#rewrite_by_lua). For example, - -```nginx - - location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; - } -``` - -can be implemented in ngx_lua as: - -```nginx - - location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; - } - - location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - return ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; - } -``` - -Just as any other rewrite phase handlers, [rewrite_by_lua](#rewrite_by_lua) also runs in subrequests. - -Note that when calling `ngx.exit(ngx.OK)` within a [rewrite_by_lua](#rewrite_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [rewrite_by_lua](#rewrite_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. - -If the [ngx_http_rewrite_module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite) directive is used to change the URI and initiate location re-lookups (internal redirections), then any [rewrite_by_lua](#rewrite_by_lua) or [rewrite_by_lua_file](#rewrite_by_lua_file) code sequences within the current location will not be executed. For example, - -```nginx - - location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; - } - location /bar { - ... - } -``` - -Here the Lua code `ngx.exit(503)` will never run. This will be the case if `rewrite ^ /bar last` is used as this will similarly initiate an internal redirection. If the `break` modifier is used instead, there will be no internal redirection and the `rewrite_by_lua` code will be executed. - -The `rewrite_by_lua` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. - -[Back to TOC](#directives) - -rewrite_by_lua_block --------------------- - -**syntax:** *rewrite_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Similar to the [rewrite_by_lua](#rewrite_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - rewrite_by_lua_block { - do_something("hello, world!\nhiya\n") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -rewrite_by_lua_file -------------------- - -**syntax:** *rewrite_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *rewrite tail* - -Equivalent to [rewrite_by_lua](#rewrite_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached and the Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid reloading Nginx. - -The `rewrite_by_lua_file` code will always run at the end of the `rewrite` request-processing phase unless [rewrite_by_lua_no_postpone](#rewrite_by_lua_no_postpone) is turned on. - -Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). - -[Back to TOC](#directives) - -access_by_lua -------------- - -**syntax:** *access_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [access_by_lua_block](#access_by_lua_block) directive instead. - -Acts as an access phase handler and executes Lua code string specified in `` for every request. -The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox). - -Note that this handler always runs *after* the standard [ngx_http_access_module](http://nginx.org/en/docs/http/ngx_http_access_module.html). So the following will work as expected: - -```nginx - - location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... - } -``` - -That is, if a client IP address is in the blacklist, it will be denied before the MySQL query for more complex authentication is executed by [access_by_lua](#access_by_lua). - -Note that the [ngx_auth_request](http://mdounin.ru/hg/ngx_http_auth_request_module/) module can be approximated by using [access_by_lua](#access_by_lua): - -```nginx - - location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } -``` - -can be implemented in ngx_lua as: - -```nginx - - location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } -``` - -As with other access phase handlers, [access_by_lua](#access_by_lua) will *not* run in subrequests. - -Note that when calling `ngx.exit(ngx.OK)` within a [access_by_lua](#access_by_lua) handler, the nginx request processing control flow will still continue to the content handler. To terminate the current request from within a [access_by_lua](#access_by_lua) handler, calling [ngx.exit](#ngxexit) with status >= 200 (`ngx.HTTP_OK`) and status < 300 (`ngx.HTTP_SPECIAL_RESPONSE`) for successful quits and `ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)` (or its friends) for failures. - -Starting from the `v0.9.20` release, you can use the [access_by_lua_no_postpone](#access_by_lua_no_postpone) -directive to control when to run this handler inside the "access" request-processing phase -of NGINX. - -[Back to TOC](#directives) - -access_by_lua_block -------------------- - -**syntax:** *access_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -Similar to the [access_by_lua](#access_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - access_by_lua_block { - do_something("hello, world!\nhiya\n") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -access_by_lua_file ------------------- - -**syntax:** *access_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *access tail* - -Equivalent to [access_by_lua](#access_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -Nginx variables can be used in the `` string to provide flexibility. This however carries some risks and is not ordinarily recommended. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -When the Lua code cache is turned on (by default), the user code is loaded once at the first request and cached -and the Nginx config must be reloaded each time the Lua source file is modified. -The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid repeatedly reloading Nginx. - -Nginx variables are supported in the file path for dynamic dispatch just as in [content_by_lua_file](#content_by_lua_file). - -[Back to TOC](#directives) - -header_filter_by_lua --------------------- - -**syntax:** *header_filter_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [header_filter_by_lua_block](#header_filter_by_lua_block) directive instead. - -Uses Lua code specified in `` to define an output header filter. - -Note that the following API functions are currently disabled within this context: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.redirect](#ngxredirect) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Here is an example of overriding a response header (or adding one if absent) in our Lua header filter: - -```nginx - - location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; - } -``` - -This directive was first introduced in the `v0.2.1rc20` release. - -[Back to TOC](#directives) - -header_filter_by_lua_block --------------------------- - -**syntax:** *header_filter_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Similar to the [header_filter_by_lua](#header_filter_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - header_filter_by_lua_block { - ngx.header["content-length"] = nil - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -header_filter_by_lua_file -------------------------- - -**syntax:** *header_filter_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *output-header-filter* - -Equivalent to [header_filter_by_lua](#header_filter_by_lua), except that the file specified by `` contains the Lua code, or as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.2.1rc20` release. - -[Back to TOC](#directives) - -body_filter_by_lua ------------------- - -**syntax:** *body_filter_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [body_filter_by_lua_block](#body_filter_by_lua_block) directive instead. - -Uses Lua code specified in `` to define an output body filter. - -The input data chunk is passed via [ngx.arg](#ngxarg)\[1\] (as a Lua string value) and the "eof" flag indicating the end of the response body data stream is passed via [ngx.arg](#ngxarg)\[2\] (as a Lua boolean value). - -Behind the scene, the "eof" flag is just the `last_buf` (for main requests) or `last_in_chain` (for subrequests) flag of the Nginx chain link buffers. (Before the `v0.7.14` release, the "eof" flag does not work at all in subrequests.) - -The output data stream can be aborted immediately by running the following Lua statement: - -```lua - - return ngx.ERROR -``` - -This will truncate the response body and usually result in incomplete and also invalid responses. - -The Lua code can pass its own modified version of the input data chunk to the downstream Nginx output body filters by overriding [ngx.arg](#ngxarg)\[1\] with a Lua string or a Lua table of strings. For example, to transform all the lowercase letters in the response body, we can just write: - -```nginx - - location / { - proxy_pass http://mybackend; - body_filter_by_lua 'ngx.arg[1] = string.upper(ngx.arg[1])'; - } -``` - -When setting `nil` or an empty Lua string value to `ngx.arg[1]`, no data chunk will be passed to the downstream Nginx output filters at all. - -Likewise, new "eof" flag can also be specified by setting a boolean value to [ngx.arg](#ngxarg)\[2\]. For example, - -```nginx - - location /t { - echo hello world; - echo hiya globe; - - body_filter_by_lua ' - local chunk = ngx.arg[1] - if string.match(chunk, "hello") then - ngx.arg[2] = true -- new eof - return - end - - -- just throw away any remaining chunk data - ngx.arg[1] = nil - '; - } -``` - -Then `GET /t` will just return the output - - - hello world - - -That is, when the body filter sees a chunk containing the word "hello", then it will set the "eof" flag to true immediately, resulting in truncated but still valid responses. - -When the Lua code may change the length of the response body, then it is required to always clear out the `Content-Length` response header (if any) in a header filter to enforce streaming output, as in - -```nginx - - location /foo { - # fastcgi_pass/proxy_pass/... - - header_filter_by_lua_block { ngx.header.content_length = nil } - body_filter_by_lua 'ngx.arg[1] = string.len(ngx.arg[1]) .. "\\n"'; - } -``` - -Note that the following API functions are currently disabled within this context due to the limitations in NGINX output filter's current implementation: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit) and [ngx.exec](#ngxexec)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Nginx output filters may be called multiple times for a single request because response body may be delivered in chunks. Thus, the Lua code specified by in this directive may also run multiple times in the lifetime of a single HTTP request. - -This directive was first introduced in the `v0.5.0rc32` release. - -[Back to TOC](#directives) - -body_filter_by_lua_block ------------------------- - -**syntax:** *body_filter_by_lua_block { lua-script-str }* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Similar to the [body_filter_by_lua](#body_filter_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - body_filter_by_lua_block { - local data, eof = ngx.arg[1], ngx.arg[2] - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -body_filter_by_lua_file ------------------------ - -**syntax:** *body_filter_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *output-body-filter* - -Equivalent to [body_filter_by_lua](#body_filter_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc32` release. - -[Back to TOC](#directives) - -log_by_lua ----------- - -**syntax:** *log_by_lua <lua-script-str>* - -**context:** *http, server, location, location if* - -**phase:** *log* - -**NOTE** Use of this directive is *discouraged* following the `v0.9.17` release. Use the [log_by_lua_block](#log_by_lua_block) directive instead. - -Runs the Lua source code inlined as the `` at the `log` request processing phase. This does not replace the current access logs, but runs before. - -Note that the following API functions are currently disabled within this context: - -* Output API functions (e.g., [ngx.say](#ngxsay) and [ngx.send_headers](#ngxsend_headers)) -* Control API functions (e.g., [ngx.exit](#ngxexit)) -* Subrequest API functions (e.g., [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi)) -* Cosocket API functions (e.g., [ngx.socket.tcp](#ngxsockettcp) and [ngx.req.socket](#ngxreqsocket)). - -Here is an example of gathering average data for [$upstream_response_time](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_response_time): - -```nginx - - lua_shared_dict log_dict 5M; - - server { - location / { - proxy_pass http://mybackend; - - log_by_lua ' - local log_dict = ngx.shared.log_dict - local upstream_time = tonumber(ngx.var.upstream_response_time) - - local sum = log_dict:get("upstream_time-sum") or 0 - sum = sum + upstream_time - log_dict:set("upstream_time-sum", sum) - - local newval, err = log_dict:incr("upstream_time-nb", 1) - if not newval and err == "not found" then - log_dict:add("upstream_time-nb", 0) - log_dict:incr("upstream_time-nb", 1) - end - '; - } - - location = /status { - content_by_lua_block { - local log_dict = ngx.shared.log_dict - local sum = log_dict:get("upstream_time-sum") - local nb = log_dict:get("upstream_time-nb") - - if nb and sum then - ngx.say("average upstream response time: ", sum / nb, - " (", nb, " reqs)") - else - ngx.say("no data yet") - end - } - } - } -``` - -This directive was first introduced in the `v0.5.0rc31` release. - -[Back to TOC](#directives) - -log_by_lua_block ----------------- - -**syntax:** *log_by_lua_block { lua-script }* - -**context:** *http, server, location, location if* - -**phase:** *log* - -Similar to the [log_by_lua](#log_by_lua) directive except that this directive inlines -the Lua source directly -inside a pair of curly braces (`{}`) instead of in an NGINX string literal (which requires -special character escaping). - -For instance, - -```nginx - - log_by_lua_block { - print("I need no extra escaping here, for example: \r\nblah") - } -``` - -This directive was first introduced in the `v0.9.17` release. - -[Back to TOC](#directives) - -log_by_lua_file ---------------- - -**syntax:** *log_by_lua_file <path-to-lua-script-file>* - -**context:** *http, server, location, location if* - -**phase:** *log* - -Equivalent to [log_by_lua](#log_by_lua), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.5.0rc31` release. - -[Back to TOC](#directives) - -balancer_by_lua_block ---------------------- - -**syntax:** *balancer_by_lua_block { lua-script }* - -**context:** *upstream* - -**phase:** *content* - -This directive runs Lua code as an upstream balancer for any upstream entities defined -by the `upstream {}` configuration block. - -For instance, - -```nginx - - upstream foo { - server 127.0.0.1; - balancer_by_lua_block { - -- use Lua to do something interesting here - -- as a dynamic balancer - } - } - - server { - location / { - proxy_pass http://foo; - } - } -``` - -The resulting Lua load balancer can work with any existing nginx upstream modules -like [ngx_proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) and -[ngx_fastcgi](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html). - -Also, the Lua load balancer can work with the standard upstream connection pool mechanism, -i.e., the standard [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive. -Just ensure that the [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive -is used *after* this `balancer_by_lua_block` directive in a single `upstream {}` configuration block. - -The Lua load balancer can totally ignore the list of servers defined in the `upstream {}` block -and select peer from a completely dynamic server list (even changing per request) via the -[ngx.balancer](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md) module -from the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. - -The Lua code handler registered by this directive might get called more than once in a single -downstream request when the nginx upstream mechanism retries the request on conditions -specified by directives like the [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream) -directive. - -This Lua code execution context does not support yielding, so Lua APIs that may yield -(like cosockets and "light threads") are disabled in this context. One can usually work -around this limitation by doing such operations in an earlier phase handler (like -[access_by_lua*](#access_by_lua)) and passing along the result into this context -via the [ngx.ctx](#ngxctx) table. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -balancer_by_lua_file --------------------- - -**syntax:** *balancer_by_lua_file <path-to-lua-script-file>* - -**context:** *upstream* - -**phase:** *content* - -Equivalent to [balancer_by_lua_block](#balancer_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -lua_need_request_body ---------------------- - -**syntax:** *lua_need_request_body <on|off>* - -**default:** *off* - -**context:** *http, server, location, location if* - -**phase:** *depends on usage* - -Determines whether to force the request body data to be read before running rewrite/access/access_by_lua* or not. The Nginx core does not read the client request body by default and if request body data is required, then this directive should be turned `on` or the [ngx.req.read_body](#ngxreqread_body) function should be called within the Lua code. - -To read the request body data within the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable, -[client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) must have the same value as [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size). Because when the content length exceeds [client_body_buffer_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) but less than [client_max_body_size](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size), Nginx will buffer the data into a temporary file on the disk, which will lead to empty value in the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable. - -If the current location includes [rewrite_by_lua*](#rewrite_by_lua) directives, -then the request body will be read just before the [rewrite_by_lua*](#rewrite_by_lua) code is run (and also at the -`rewrite` phase). Similarly, if only [content_by_lua](#content_by_lua) is specified, -the request body will not be read until the content handler's Lua code is -about to run (i.e., the request body will be read during the content phase). - -It is recommended however, to use the [ngx.req.read_body](#ngxreqread_body) and [ngx.req.discard_body](#ngxreqdiscard_body) functions for finer control over the request body reading process instead. - -This also applies to [access_by_lua*](#access_by_lua). - -[Back to TOC](#directives) - -ssl_certificate_by_lua_block ----------------------------- - -**syntax:** *ssl_certificate_by_lua_block { lua-script }* - -**context:** *server* - -**phase:** *right-before-SSL-handshake* - -This directive runs user Lua code when NGINX is about to start the SSL handshake for the downstream -SSL (https) connections. - -It is particularly useful for setting the SSL certificate chain and the corresponding private key on a per-request -basis. It is also useful to load such handshake configurations nonblockingly from the remote (for example, -with the [cosocket](#ngxsockettcp) API). And one can also do per-request OCSP stapling handling in pure -Lua here as well. - -Another typical use case is to do SSL handshake traffic control nonblockingly in this context, -with the help of the [lua-resty-limit-traffic#readme](https://github.com/openresty/lua-resty-limit-traffic) -library, for example. - -One can also do interesting things with the SSL handshake requests from the client side, like -rejecting old SSL clients using the SSLv3 protocol or even below selectively. - -The [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) -and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) Lua modules -provided by the [lua-resty-core](https://github.com/openresty/lua-resty-core/#readme) -library are particularly useful in this context. You can use the Lua API offered by these two Lua modules -to manipulate the SSL certificate chain and private key for the current SSL connection -being initiated. - -This Lua handler does not run at all, however, when NGINX/OpenSSL successfully resumes -the SSL session via SSL session IDs or TLS session tickets for the current SSL connection. In -other words, this Lua handler only runs when NGINX has to initiate a full SSL handshake. - -Below is a trivial example using the -[ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) module -at the same time: - -```nginx - - server { - listen 443 ssl; - server_name test.com; - - ssl_certificate_by_lua_block { - print("About to initiate a new SSL handshake!") - } - - location / { - root html; - } - } -``` - -See more complicated examples in the [ngx.ssl](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md) -and [ngx.ocsp](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ocsp.md) -Lua modules' official documentation. - -Uncaught Lua exceptions in the user Lua code immediately abort the current SSL session, so does the -[ngx.exit](#ngxexit) call with an error code like `ngx.ERROR`. - -This Lua code execution context *does* support yielding, so Lua APIs that may yield -(like cosockets, sleeping, and "light threads") -are enabled in this context. - -Note, however, you still need to configure the [ssl_certificate](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate) and -[ssl_certificate_key](http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_certificate_key) -directives even though you will not use this static certificate and private key at all. This is -because the NGINX core requires their appearance otherwise you are seeing the following error -while starting NGINX: - - - nginx: [emerg] no ssl configured for the server - - -This directive currently requires the following NGINX core patch to work correctly: - - - -The bundled version of the NGINX core in OpenResty 1.9.7.2 (or above) already has this -patch applied. - -Furthermore, one needs at least OpenSSL 1.0.2e for this directive to work. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -ssl_certificate_by_lua_file ---------------------------- - -**syntax:** *ssl_certificate_by_lua_file <path-to-lua-script-file>* - -**context:** *server* - -**phase:** *right-before-SSL-handshake* - -Equivalent to [ssl_certificate_by_lua_block](#ssl_certificate_by_lua_block), except that the file specified by `` contains the Lua code, or, as from the `v0.5.0rc32` release, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.0` release. - -[Back to TOC](#directives) - -ssl_session_fetch_by_lua_block ------------------------------- - -**syntax:** *ssl_session_fetch_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *right-before-SSL-handshake* - -This directive runs Lua code to look up and load the SSL session (if any) according to the session ID -provided by the current SSL handshake request for the downstream. - -The Lua API for obtaining the current session ID and loading a cached SSL session data -is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md) -Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) -library. - -Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), -are enabled in this context. - -This hook, together with the [ssl_session_store_by_lua*](#ssl_session_store_by_lua_block) hook, -can be used to implement distributed caching mechanisms in pure Lua (based -on the [cosocket](#ngxsockettcp) API, for example). If a cached SSL session is found -and loaded into the current SSL connection context, -SSL session resumption can then get immediately initiated and bypass the full SSL handshake process which is very expensive in terms of CPU time. - -Please note that TLS session tickets are very different and it is the clients' responsibility -to cache the SSL session state when session tickets are used. SSL session resumptions based on -TLS session tickets would happen automatically without going through this hook (nor the -[ssl_session_store_by_lua_block](#ssl_session_store_by_lua) hook). This hook is mainly -for older or less capable SSL clients that can only do SSL sessions by session IDs. - -When [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) is specified at the same time, -this hook usually runs before [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block). -When the SSL session is found and successfully loaded for the current SSL connection, -SSL session resumption will happen and thus bypass the [ssl_certificate_by_lua*](#ssl_certificate_by_lua_block) -hook completely. In this case, NGINX also bypasses the [ssl_session_store_by_lua_block](#ssl_session_store_by_lua) -hook, for obvious reasons. - -To easily test this hook locally with a modern web browser, you can temporarily put the following line -in your https server block to disable the TLS session ticket support: - - ssl_session_tickets off; - -But do not forget to comment this line out before publishing your site to the world. - -If you are using the [official pre-built packages](http://openresty.org/en/linux-packages.html) for [OpenResty](https://openresty.org/) -1.11.2.1 or later, then everything should work out of the box. - -If you are using OpenSSL libraries not provided by [OpenResty](https://openresty.org), -then you need to apply the following patch for OpenSSL 1.0.2h or later: - - - -If you are not using the NGINX core shipped with [OpenResty](https://openresty.org) 1.11.2.1 or later, then you need to -apply the following patch to the standard NGINX core 1.11.2 or later: - - - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_fetch_by_lua_file ------------------------------ - -**syntax:** *ssl_session_fetch_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *right-before-SSL-handshake* - -Equivalent to [ssl_session_fetch_by_lua_block](#ssl_session_fetch_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_store_by_lua_block ------------------------------- - -**syntax:** *ssl_session_store_by_lua_block { lua-script }* - -**context:** *http* - -**phase:** *right-after-SSL-handshake* - -This directive runs Lua code to fetch and save the SSL session (if any) according to the session ID -provided by the current SSL handshake request for the downstream. The saved or cached SSL -session data can be used for future SSL connections to resume SSL sessions without going -through the full SSL handshake process (which is very expensive in terms of CPU time). - -Lua APIs that may yield, like [ngx.sleep](#ngxsleep) and [cosockets](#ngxsockettcp), -are *disabled* in this context. You can still, however, use the [ngx.timer.at](#ngxtimerat) API -to create 0-delay timers to save the SSL session data asynchronously to external services (like `redis` or `memcached`). - -The Lua API for obtaining the current session ID and the associated session state data -is provided in the [ngx.ssl.session](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl/session.md#readme) -Lua module shipped with the [lua-resty-core](https://github.com/openresty/lua-resty-core#readme) -library. - -To easily test this hook locally with a modern web browser, you can temporarily put the following line -in your https server block to disable the TLS session ticket support: - - ssl_session_tickets off; - -But do not forget to comment this line out before publishing your site to the world. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -ssl_session_store_by_lua_file ------------------------------ - -**syntax:** *ssl_session_store_by_lua_file <path-to-lua-script-file>* - -**context:** *http* - -**phase:** *right-after-SSL-handshake* - -Equivalent to [ssl_session_store_by_lua_block](#ssl_session_store_by_lua_block), except that the file specified by `` contains the Lua code, or rather, the [Lua/LuaJIT bytecode](#lualuajit-bytecode-support) to be executed. - -When a relative path like `foo/bar.lua` is given, they will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option while starting the Nginx server. - -This directive was first introduced in the `v0.10.6` release. - -Note that: this directive is only allowed to used in **http context** from the `v0.10.7` release -(because SSL session resumption happens before server name dispatch). - -[Back to TOC](#directives) - -lua_shared_dict ---------------- - -**syntax:** *lua_shared_dict <name> <size>* - -**default:** *no* - -**context:** *http* - -**phase:** *depends on usage* - -Declares a shared memory zone, ``, to serve as storage for the shm based Lua dictionary `ngx.shared.`. - -Shared memory zones are always shared by all the nginx worker processes in the current nginx server instance. - -The `` argument accepts size units such as `k` and `m`: - -```nginx - - http { - lua_shared_dict dogs 10m; - ... - } -``` - -The hard-coded minimum size is 8KB while the practical minimum size depends -on actual user data set (some people start with 12KB). - -See [ngx.shared.DICT](#ngxshareddict) for details. - -This directive was first introduced in the `v0.3.1rc22` release. - -[Back to TOC](#directives) - -lua_socket_connect_timeout --------------------------- - -**syntax:** *lua_socket_connect_timeout <time>* - -**default:** *lua_socket_connect_timeout 60s* - -**context:** *http, server, location* - -This directive controls the default timeout value used in TCP/unix-domain socket object's [connect](#tcpsockconnect) method and can be overridden by the [settimeout](#tcpsocksettimeout) or [settimeouts](#tcpsocksettimeouts) methods. - -The `