Compare commits

...
66 Commits
Author SHA1 Message Date
Hakase 008819315c Update README.md 2020-10-05 21:35:23 +09:00
Hakase 677450910d Submodule update, fix build error. 2020-10-05 21:34:12 +09:00
Hakase d23cd2f0e0 Latest update - 7702 2020-08-29 19:53:01 +09:00
Hakase 72680e2bd2 Version bump - v1.19.3 2020-08-29 19:52:51 +09:00
Hakase 10689fcf23 Release - v1.19.2 2020-08-29 19:52:37 +09:00
Hakase c8ca86a8d2 Latest update - 7698 2020-08-29 19:52:20 +09:00
Hakase 9b69c0a792 Submodule update. 2020-07-12 20:03:05 +09:00
Hakase 38112b0b03 Latest update - 7684 2020-07-12 20:01:50 +09:00
Hakase 8407b245de Version bump - v1.19.2 2020-07-12 20:01:36 +09:00
Hakase cdf4d451e4 Release - v1.19.1 2020-07-12 20:01:21 +09:00
Hakase 141b7448a4 Latest update - 7680 2020-07-12 20:00:53 +09:00
Hakase b54c866079 Latest update - 7672 2020-07-01 15:21:18 +09:00
Hakase f1c30863fd Latest update - 7671 2020-06-28 19:20:30 +09:00
Hakase d3a0c6f60b Latest update - 7665 2020-06-15 01:33:51 +09:00
Hakase da1c2b041b Latest update - 7661 2020-05-27 20:32:16 +09:00
Hakase 605baf04af Version bump - v1.19.1 2020-05-27 20:32:04 +09:00
Hakase e5ed7cb934 Release - v1.19.0 2020-05-27 20:31:46 +09:00
Hakase b839120943 Latest update - 7655 2020-05-25 20:36:22 +09:00
Hakase da5d29fcc3 Fix README.md (OpenSSL version) 2020-05-17 20:33:33 +09:00
Hakase a204ef38f1 Submodule update. 2020-05-17 20:31:41 +09:00
Hakase 840eeb7822 Latest update - 7649 2020-05-17 20:30:28 +09:00
Hakase b44a2acbe4 Latest update - 7648 2020-05-09 15:33:53 +09:00
Hakase 5343d2bbc5 Edit submodule - ngx_brotli 2020-05-02 00:02:16 +09:00
Hakase 0ad16b54fb Submodule update. (OpenSSL) 2020-04-30 00:06:27 +09:00
Hakase 5dd8c93d82 Submodule update. (fix header) 2020-04-30 00:03:01 +09:00
Hakase ce239236e3 Submodule update. 2020-04-29 23:53:09 +09:00
Hakase 2c96cb11ab Submodule update. 2020-04-25 21:11:30 +09:00
Hakase f0749362b8 Submodule update. 2020-04-25 20:23:22 +09:00
Hakase 17760a9544 Latest update - 7647 2020-04-25 19:55:22 +09:00
Hakase 73d234d143 Version bump - v1.19.0 2020-04-25 19:55:02 +09:00
Hakase 0d55d860d8 Release - v1.18.0 2020-04-25 19:54:38 +09:00
Hakase 214d1434e0 Version bump - v1.17.11 2020-04-15 18:40:12 +09:00
Hakase b09da0b6bc Release - v1.17.10 2020-04-15 18:39:55 +09:00
Hakase cacff59229 Latest update - 7639 2020-04-15 18:39:36 +09:00
Hakase 31970d8a16 Latest update - 7638 2020-04-14 12:44:32 +09:00
Hakase d62ff9ef6d Latest update - 7637 2020-03-17 16:19:44 +09:00
Hakase 0e342ce410 Update special response. 2020-03-08 21:45:18 +09:00
Hakase 17c9415840 Submodule update. 2020-03-08 13:12:24 +09:00
Hakase b882d7f6f8 Version bump - v1.17.10 2020-03-04 08:50:28 +09:00
Hakase c80cd29962 Release - v1.17.9 2020-03-04 08:49:59 +09:00
Hakase 7ed9723455 Latest update - 7633 2020-03-04 08:48:31 +09:00
Hakase c58ddf89e9 Submodule update. 2020-03-03 19:23:04 +09:00
Hakase 49dbf201ac Latest update - 7632 2020-03-03 18:15:29 +09:00
Hakase a5a19139a3 Latest update - 7630 2020-02-28 23:44:39 +09:00
Hakase 801540a2d5 Latest update - 7628 2020-02-28 12:37:52 +09:00
Hakase 980e7d0358 Latest update - 7627 2020-02-21 08:51:06 +09:00
Hakase d477388bae Fix build error - naxsi 2020-02-17 21:36:49 +09:00
Hakase 795a5f5d70 Latest update - 7624 2020-02-13 08:43:38 +09:00
Hakase c975811c7b Submodule update. 2020-02-11 23:23:09 +09:00
Hakase 5a5ea54d48 Latest update - 7623 2020-02-07 01:31:27 +09:00
Hakase fd07a01249 Fix nginx.conf (Cloudflare IPs) 2020-01-27 18:34:36 +09:00
Hakase f6849c3590 Version bump - v1.17.9 2020-01-22 16:59:20 +09:00
Hakase ab20392497 Release - v1.17.8 2020-01-22 16:58:56 +09:00
Hakase 347c3f34fe Edit config.inc.example 2020-01-22 16:58:15 +09:00
Hakase 3850d60a81 Submodule update. 2020-01-22 16:37:22 +09:00
Hakase de1993b3e5 Submodule update. 2020-01-21 11:01:18 +09:00
Hakase 796de73034 Submodule update. 2020-01-17 19:47:15 +09:00
Hakase 978d81dd1b Latest update - 7618 2020-01-17 19:40:11 +09:00
Hakase df26e63ebf Submodule update. 2020-01-09 22:20:57 +09:00
Hakase bcbd6417f6 Latest update - 7617 2019-12-28 20:18:39 +09:00
Hakase 1a084f42db Version bump - v1.17.8 2019-12-25 00:35:32 +09:00
Hakase 1d1103eacb Release - v1.17.7 2019-12-25 00:35:18 +09:00
Hakase b013300457 Latest update - 7600 2019-12-06 22:48:23 +09:00
Hakase f898acf52b Version bump - v1.17.7 2019-11-23 11:46:15 +09:00
Hakase 2fc052617a Release - v1.17.6 2019-11-23 11:45:56 +09:00
Hakase d9ff2e8286 Latest update - 7596 2019-11-23 11:45:34 +09:00
74 changed files with 3626 additions and 725 deletions
+3 -3
View File
@@ -7,9 +7,6 @@
[submodule "lib/nginx-dav-ext-module"] [submodule "lib/nginx-dav-ext-module"]
path = lib/nginx-dav-ext-module path = lib/nginx-dav-ext-module
url = https://github.com/arut/nginx-dav-ext-module.git url = https://github.com/arut/nginx-dav-ext-module.git
[submodule "lib/ngx_brotli"]
path = lib/ngx_brotli
url = https://github.com/eustas/ngx_brotli.git
[submodule "lib/ngx_devel_kit"] [submodule "lib/ngx_devel_kit"]
path = lib/ngx_devel_kit path = lib/ngx_devel_kit
url = https://github.com/simplresty/ngx_devel_kit.git url = https://github.com/simplresty/ngx_devel_kit.git
@@ -35,3 +32,6 @@
[submodule "lib/nginx-http-flv-module"] [submodule "lib/nginx-http-flv-module"]
path = lib/nginx-http-flv-module path = lib/nginx-http-flv-module
url = https://github.com/winshining/nginx-http-flv-module.git url = https://github.com/winshining/nginx-http-flv-module.git
[submodule "lib/ngx_brotli"]
path = lib/ngx_brotli
url = https://github.com/google/ngx_brotli.git
+8
View File
@@ -444,3 +444,11 @@ d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9
ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3 ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3
ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4 ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4
9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5 9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5
de68d0d94320cbf033599c6f3ca37e5335c67fd7 release-1.17.6
e56295fe0ea76bf53b06bffa77a2d3a9a335cb8c release-1.17.7
fdacd273711ddf20f778c1fb91529ab53979a454 release-1.17.8
5e8d52bca714d4b85284ddb649d1ba4a3ca978a8 release-1.17.9
c44970de01474f6f3e01b0adea85ec1d03e3a5f2 release-1.17.10
cbe6ba650211541310618849168631ce0b788f35 release-1.19.0
062920e2f3bf871ef7a3d8496edec1b3065faf80 release-1.19.1
a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2
+4 -2
View File
@@ -1,6 +1,8 @@
# Hakase-nginx # Hakase-nginx
**My nginx build files.** **My nginx build files.**
## This repository is no longer operational. Use an alternative such as tengine.
Example Web Server - [https://ssl.haka.se/](https://ssl.haka.se/) Example Web Server - [https://ssl.haka.se/](https://ssl.haka.se/)
## Please install dependency library. ## Please install dependency library.
@@ -33,8 +35,8 @@ Example Web Server - [https://ssl.haka.se/](https://ssl.haka.se/)
- Use the settings below to support older browsers. (TLS Protocol) - Use the settings below to support older browsers. (TLS Protocol)
- ssl_protocols : TLSv1 TLSv1.1 TLSv1.2 TLSv1.3 - ssl_protocols : TLSv1 TLSv1.1 TLSv1.2 TLSv1.3
- ssl_ciphers : [TLS13+AESGCM+AES128|TLS13+CHACHA20]:TLS13+AESGCM+AES256:[EECDH+ECDSA+AESGCM+AES128|EECDH+ECDSA+CHACHA20]:EECDH+ECDSA+AESGCM+AES256:EECDH+ECDSA+AES128+SHA:EECDH+ECDSA+AES256+SHA:[EECDH+aRSA+AESGCM+AES128|EECDH+aRSA+CHACHA20]:EECDH+aRSA+AESGCM+AES256:EECDH+aRSA+AES128+SHA:EECDH+aRSA+AES256+SHA:RSA+AES128+SHA:RSA+AES256+SHA:RSA+3DES - ssl_ciphers : [TLS13+AESGCM+AES128|TLS13+CHACHA20]:TLS13+AESGCM+AES256:[EECDH+ECDSA+AESGCM+AES128|EECDH+ECDSA+CHACHA20]:EECDH+ECDSA+AESGCM+AES256:EECDH+ECDSA+AES128+SHA:EECDH+ECDSA+AES256+SHA:[EECDH+aRSA+AESGCM+AES128|EECDH+aRSA+CHACHA20]:EECDH+aRSA+AESGCM+AES256:EECDH+aRSA+AES128+SHA:EECDH+aRSA+AES256+SHA:RSA+AES128+SHA:RSA+AES256+SHA:RSA+3DES
- TLS v1.3 (**final**) - TLS v1.3
- Use OpenSSL-3.0.0-dev (**final**) - Use OpenSSL-3.0.0-alpha3-dev
- Use OpenSSL equal preference patch ([BoringSSL](https://github.com/google/boringssl) & [buik](https://gitlab.com/buik/openssl/blob/openssl-patch/openssl-1.1)) - Use OpenSSL equal preference patch ([BoringSSL](https://github.com/google/boringssl) & [buik](https://gitlab.com/buik/openssl/blob/openssl-patch/openssl-1.1))
- My OpenSSL patch is [here](https://github.com/hakasenyang/openssl-patch). - My OpenSSL patch is [here](https://github.com/hakasenyang/openssl-patch).
- Prefers ChaCha20 suites with clients that don't have AES-NI(AES hardware acceleration) (e.g., Android devices) - Prefers ChaCha20 suites with clients that don't have AES-NI(AES hardware acceleration) (e.g., Android devices)
+2 -2
View File
@@ -102,9 +102,9 @@ if [ "$GEOIP2" = 1 ]; then BUILD_MODULES="${BUILD_MODULES} --add-module=./lib/ng
if [ "$VTS" = 1 ]; then BUILD_MODULES="${BUILD_MODULES} --add-module=./lib/nginx-module-vts"; fi if [ "$VTS" = 1 ]; then BUILD_MODULES="${BUILD_MODULES} --add-module=./lib/nginx-module-vts"; fi
auto/configure \ auto/configure \
--with-cc-opt="-DTCP_FASTOPEN=23 ${BUILD_BIT}${BUILD_LTO} ${TEMP_OPT} -g -O3 -march=native -fstack-protector-strong -fuse-ld=gold -fuse-linker-plugin --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wno-strict-aliasing -Wp,-D_FORTIFY_SOURCE=2 -gsplit-dwarf -DNGX_HTTP_HEADERS" \ --with-cc-opt="-Wno-stringop-truncation -DTCP_FASTOPEN=23 ${BUILD_BIT}${BUILD_LTO} ${TEMP_OPT} -g -O3 -march=native -fstack-protector-strong -fuse-ld=gold -fuse-linker-plugin --param=ssp-buffer-size=4 -Wformat -Werror=format-security -Wno-strict-aliasing -Wp,-D_FORTIFY_SOURCE=2 -gsplit-dwarf -DNGX_HTTP_HEADERS" \
--with-ld-opt="${BUILD_LD} ${BUILD_LTO}" \ --with-ld-opt="${BUILD_LD} ${BUILD_LTO}" \
--with-openssl-opt="enable-weak-ssl-ciphers no-ssl3-method -march=native -ljemalloc ${BUILD_OPENSSL_LTO}" \ --with-openssl-opt="no-cmp enable-weak-ssl-ciphers no-ssl3-method -march=native -ljemalloc ${BUILD_OPENSSL_LTO}" \
--builddir=objs --prefix=${NGX_PREFIX} \ --builddir=objs --prefix=${NGX_PREFIX} \
--conf-path=${NGX_CONF} \ --conf-path=${NGX_CONF} \
--pid-path=${NGX_PID} \ --pid-path=${NGX_PID} \
+23 -18
View File
@@ -31,24 +31,29 @@ http {
variables_hash_max_size 2048; variables_hash_max_size 2048;
# Cloudflare CDN # Cloudflare CDN
set_real_ip_from 199.27.128.0/21; # IPv4
set_real_ip_from 173.245.48.0/20; set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22; set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18; set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18; set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20; set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20; set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22; set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17; set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15; set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/12; set_real_ip_from 104.16.0.0/12;
#set_real_ip_from 2400:cb00::/32; set_real_ip_from 172.64.0.0/13;
#set_real_ip_from 2606:4700::/32; set_real_ip_from 131.0.72.0/22;
#set_real_ip_from 2803:f800::/32; # IPv6
#set_real_ip_from 2405:b500::/32; #set_real_ip_from 2400:cb00::/32;
#set_real_ip_from 2405:8100::/32; #set_real_ip_from 2606:4700::/32;
#set_real_ip_from 2803:f800::/32;
#set_real_ip_from 2405:b500::/32;
#set_real_ip_from 2405:8100::/32;
#set_real_ip_from 2a06:98c0::/29;
#set_real_ip_from 2c0f:f248::/32;
real_ip_header CF-Connecting-IP; real_ip_header CF-Connecting-IP;
# SSL Config # SSL Config
+1 -1
View File
@@ -21,7 +21,7 @@ BUILD_MTS="-j$(expr $(nproc) \+ 1)"
### LTO build ### LTO build
### View : https://gcc.gnu.org/wiki/LinkTimeOptimization#Using_LTO ### View : https://gcc.gnu.org/wiki/LinkTimeOptimization#Using_LTO
LTO=1 LTO=0
######################### #########################
### Select add module ### ### Select add module ###
+78 -8
View File
@@ -141,6 +141,7 @@ syn keyword ngxDirective contained ancient_browser_value
syn keyword ngxDirective contained api syn keyword ngxDirective contained api
syn keyword ngxDirective contained auth_basic syn keyword ngxDirective contained auth_basic
syn keyword ngxDirective contained auth_basic_user_file syn keyword ngxDirective contained auth_basic_user_file
syn keyword ngxDirective contained auth_delay
syn keyword ngxDirective contained auth_http syn keyword ngxDirective contained auth_http
syn keyword ngxDirective contained auth_http_header syn keyword ngxDirective contained auth_http_header
syn keyword ngxDirective contained auth_http_pass_client_cert syn keyword ngxDirective contained auth_http_pass_client_cert
@@ -332,6 +333,7 @@ syn keyword ngxDirective contained ip_hash
syn keyword ngxDirective contained js_access syn keyword ngxDirective contained js_access
syn keyword ngxDirective contained js_content syn keyword ngxDirective contained js_content
syn keyword ngxDirective contained js_filter syn keyword ngxDirective contained js_filter
syn keyword ngxDirective contained js_import
syn keyword ngxDirective contained js_include syn keyword ngxDirective contained js_include
syn keyword ngxDirective contained js_path syn keyword ngxDirective contained js_path
syn keyword ngxDirective contained js_preread syn keyword ngxDirective contained js_preread
@@ -348,6 +350,7 @@ syn keyword ngxDirective contained large_client_header_buffers
syn keyword ngxDirective contained least_conn syn keyword ngxDirective contained least_conn
syn keyword ngxDirective contained least_time syn keyword ngxDirective contained least_time
syn keyword ngxDirective contained limit_conn syn keyword ngxDirective contained limit_conn
syn keyword ngxDirective contained limit_conn_dry_run
syn keyword ngxDirective contained limit_conn_log_level syn keyword ngxDirective contained limit_conn_log_level
syn keyword ngxDirective contained limit_conn_status syn keyword ngxDirective contained limit_conn_status
syn keyword ngxDirective contained limit_conn_zone syn keyword ngxDirective contained limit_conn_zone
@@ -595,6 +598,9 @@ syn keyword ngxDirective contained ssl_early_data
syn keyword ngxDirective contained ssl_ecdh_curve syn keyword ngxDirective contained ssl_ecdh_curve
syn keyword ngxDirective contained ssl_engine syn keyword ngxDirective contained ssl_engine
syn keyword ngxDirective contained ssl_handshake_timeout syn keyword ngxDirective contained ssl_handshake_timeout
syn keyword ngxDirective contained ssl_ocsp
syn keyword ngxDirective contained ssl_ocsp_cache
syn keyword ngxDirective contained ssl_ocsp_responder
syn keyword ngxDirective contained ssl_password_file syn keyword ngxDirective contained ssl_password_file
syn keyword ngxDirective contained ssl_prefer_server_ciphers syn keyword ngxDirective contained ssl_prefer_server_ciphers
syn keyword ngxDirective contained ssl_preread syn keyword ngxDirective contained ssl_preread
@@ -770,6 +776,7 @@ syn keyword ngxDirectiveThirdParty contained auth_gss_authorized_principal
syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm syn keyword ngxDirectiveThirdParty contained auth_gss_force_realm
syn keyword ngxDirectiveThirdParty contained auth_gss_format_full syn keyword ngxDirectiveThirdParty contained auth_gss_format_full
syn keyword ngxDirectiveThirdParty contained auth_gss_keytab syn keyword ngxDirectiveThirdParty contained auth_gss_keytab
syn keyword ngxDirectiveThirdParty contained auth_gss_map_to_local
syn keyword ngxDirectiveThirdParty contained auth_gss_realm syn keyword ngxDirectiveThirdParty contained auth_gss_realm
syn keyword ngxDirectiveThirdParty contained auth_gss_service_name syn keyword ngxDirectiveThirdParty contained auth_gss_service_name
@@ -791,8 +798,8 @@ syn keyword ngxDirectiveThirdParty contained auth_pam_set_pam_env
" AJP protocol proxy " AJP protocol proxy
" https://github.com/yaoweibin/nginx_ajp_module " https://github.com/yaoweibin/nginx_ajp_module
syn keyword ngxDirectiveThirdParty contained ajp_buffer_size
syn keyword ngxDirectiveThirdParty contained ajp_buffers syn keyword ngxDirectiveThirdParty contained ajp_buffers
syn keyword ngxDirectiveThirdParty contained ajp_buffer_size
syn keyword ngxDirectiveThirdParty contained ajp_busy_buffers_size syn keyword ngxDirectiveThirdParty contained ajp_busy_buffers_size
syn keyword ngxDirectiveThirdParty contained ajp_cache syn keyword ngxDirectiveThirdParty contained ajp_cache
syn keyword ngxDirectiveThirdParty contained ajp_cache_key syn keyword ngxDirectiveThirdParty contained ajp_cache_key
@@ -818,6 +825,7 @@ syn keyword ngxDirectiveThirdParty contained ajp_pass_header
syn keyword ngxDirectiveThirdParty contained ajp_pass_request_body syn keyword ngxDirectiveThirdParty contained ajp_pass_request_body
syn keyword ngxDirectiveThirdParty contained ajp_pass_request_headers syn keyword ngxDirectiveThirdParty contained ajp_pass_request_headers
syn keyword ngxDirectiveThirdParty contained ajp_read_timeout syn keyword ngxDirectiveThirdParty contained ajp_read_timeout
syn keyword ngxDirectiveThirdParty contained ajp_secret
syn keyword ngxDirectiveThirdParty contained ajp_send_lowat syn keyword ngxDirectiveThirdParty contained ajp_send_lowat
syn keyword ngxDirectiveThirdParty contained ajp_send_timeout syn keyword ngxDirectiveThirdParty contained ajp_send_timeout
syn keyword ngxDirectiveThirdParty contained ajp_store syn keyword ngxDirectiveThirdParty contained ajp_store
@@ -854,8 +862,8 @@ syn keyword ngxDirectiveThirdParty contained content_handler_property
syn keyword ngxDirectiveThirdParty contained content_handler_type syn keyword ngxDirectiveThirdParty contained content_handler_type
syn keyword ngxDirectiveThirdParty contained handler_code syn keyword ngxDirectiveThirdParty contained handler_code
syn keyword ngxDirectiveThirdParty contained handler_name syn keyword ngxDirectiveThirdParty contained handler_name
syn keyword ngxDirectiveThirdParty contained handler_type
syn keyword ngxDirectiveThirdParty contained handlers_lazy_init syn keyword ngxDirectiveThirdParty contained handlers_lazy_init
syn keyword ngxDirectiveThirdParty contained handler_type
syn keyword ngxDirectiveThirdParty contained header_filter_code syn keyword ngxDirectiveThirdParty contained header_filter_code
syn keyword ngxDirectiveThirdParty contained header_filter_name syn keyword ngxDirectiveThirdParty contained header_filter_name
syn keyword ngxDirectiveThirdParty contained header_filter_property syn keyword ngxDirectiveThirdParty contained header_filter_property
@@ -871,6 +879,10 @@ syn keyword ngxDirectiveThirdParty contained jvm_options
syn keyword ngxDirectiveThirdParty contained jvm_path syn keyword ngxDirectiveThirdParty contained jvm_path
syn keyword ngxDirectiveThirdParty contained jvm_var syn keyword ngxDirectiveThirdParty contained jvm_var
syn keyword ngxDirectiveThirdParty contained jvm_workers syn keyword ngxDirectiveThirdParty contained jvm_workers
syn keyword ngxDirectiveThirdParty contained log_handler_code
syn keyword ngxDirectiveThirdParty contained log_handler_name
syn keyword ngxDirectiveThirdParty contained log_handler_property
syn keyword ngxDirectiveThirdParty contained log_handler_type
syn keyword ngxDirectiveThirdParty contained max_balanced_tcp_connections syn keyword ngxDirectiveThirdParty contained max_balanced_tcp_connections
syn keyword ngxDirectiveThirdParty contained rewrite_handler_code syn keyword ngxDirectiveThirdParty contained rewrite_handler_code
syn keyword ngxDirectiveThirdParty contained rewrite_handler_name syn keyword ngxDirectiveThirdParty contained rewrite_handler_name
@@ -879,6 +891,7 @@ syn keyword ngxDirectiveThirdParty contained rewrite_handler_type
syn keyword ngxDirectiveThirdParty contained shared_map syn keyword ngxDirectiveThirdParty contained shared_map
syn keyword ngxDirectiveThirdParty contained write_page_size syn keyword ngxDirectiveThirdParty contained write_page_size
" Certificate Transparency " Certificate Transparency
" https://github.com/grahamedgecombe/nginx-ct " https://github.com/grahamedgecombe/nginx-ct
syn keyword ngxDirectiveThirdParty contained ssl_ct syn keyword ngxDirectiveThirdParty contained ssl_ct
@@ -942,6 +955,7 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks
syn keyword ngxDirectiveThirdParty contained fancyindex_ignore syn keyword ngxDirectiveThirdParty contained fancyindex_ignore
syn keyword ngxDirectiveThirdParty contained fancyindex_localtime syn keyword ngxDirectiveThirdParty contained fancyindex_localtime
syn keyword ngxDirectiveThirdParty contained fancyindex_name_length syn keyword ngxDirectiveThirdParty contained fancyindex_name_length
syn keyword ngxDirectiveThirdParty contained fancyindex_show_dotfiles
syn keyword ngxDirectiveThirdParty contained fancyindex_show_path syn keyword ngxDirectiveThirdParty contained fancyindex_show_path
syn keyword ngxDirectiveThirdParty contained fancyindex_time_format syn keyword ngxDirectiveThirdParty contained fancyindex_time_format
@@ -991,8 +1005,8 @@ syn keyword ngxDirectiveThirdParty contained nchan_benchmark_publisher_distribut
syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution
syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel
syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time
syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string
syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id
syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string
syn keyword ngxDirectiveThirdParty contained nchan_channel_group syn keyword ngxDirectiveThirdParty contained nchan_channel_group
syn keyword ngxDirectiveThirdParty contained nchan_channel_group_accounting syn keyword ngxDirectiveThirdParty contained nchan_channel_group_accounting
syn keyword ngxDirectiveThirdParty contained nchan_channel_id syn keyword ngxDirectiveThirdParty contained nchan_channel_id
@@ -1000,6 +1014,10 @@ syn keyword ngxDirectiveThirdParty contained nchan_channel_id_split_delimiter
syn keyword ngxDirectiveThirdParty contained nchan_channel_timeout syn keyword ngxDirectiveThirdParty contained nchan_channel_timeout
syn keyword ngxDirectiveThirdParty contained nchan_deflate_message_for_websocket syn keyword ngxDirectiveThirdParty contained nchan_deflate_message_for_websocket
syn keyword ngxDirectiveThirdParty contained nchan_eventsource_event syn keyword ngxDirectiveThirdParty contained nchan_eventsource_event
syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_comment
syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_data
syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_event
syn keyword ngxDirectiveThirdParty contained nchan_eventsource_ping_interval
syn keyword ngxDirectiveThirdParty contained nchan_group_location syn keyword ngxDirectiveThirdParty contained nchan_group_location
syn keyword ngxDirectiveThirdParty contained nchan_group_max_channels syn keyword ngxDirectiveThirdParty contained nchan_group_max_channels
syn keyword ngxDirectiveThirdParty contained nchan_group_max_messages syn keyword ngxDirectiveThirdParty contained nchan_group_max_messages
@@ -1047,10 +1065,10 @@ syn keyword ngxDirectiveThirdParty contained nchan_store_messages
syn keyword ngxDirectiveThirdParty contained nchan_stub_status syn keyword ngxDirectiveThirdParty contained nchan_stub_status
syn keyword ngxDirectiveThirdParty contained nchan_sub_channel_id syn keyword ngxDirectiveThirdParty contained nchan_sub_channel_id
syn keyword ngxDirectiveThirdParty contained nchan_subscribe_existing_channels_only syn keyword ngxDirectiveThirdParty contained nchan_subscribe_existing_channels_only
syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request
syn keyword ngxDirectiveThirdParty contained nchan_subscriber syn keyword ngxDirectiveThirdParty contained nchan_subscriber
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_channel_id syn keyword ngxDirectiveThirdParty contained nchan_subscriber_channel_id
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_compound_etag_message_id syn keyword ngxDirectiveThirdParty contained nchan_subscriber_compound_etag_message_id
syn keyword ngxDirectiveThirdParty contained nchan_subscribe_request
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message syn keyword ngxDirectiveThirdParty contained nchan_subscriber_first_message
syn keyword ngxDirectiveThirdParty contained nchan_subscriber_http_raw_stream_separator 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_last_message_id
@@ -1987,11 +2005,7 @@ syn keyword ngxDirectiveThirdParty contained concat_unique
" update upstreams' config by restful interface " update upstreams' config by restful interface
" https://github.com/yzprofile/ngx_http_dyups_module " https://github.com/yzprofile/ngx_http_dyups_module
syn keyword ngxDirectiveThirdParty contained dyups_interface syn keyword ngxDirectiveThirdParty contained dyups_interface
syn keyword ngxDirectiveThirdParty contained dyups_read_msg_log
syn keyword ngxDirectiveThirdParty contained dyups_read_msg_timeout
syn keyword ngxDirectiveThirdParty contained dyups_shm_zone_size syn keyword ngxDirectiveThirdParty contained dyups_shm_zone_size
syn keyword ngxDirectiveThirdParty contained dyups_trylock
syn keyword ngxDirectiveThirdParty contained dyups_upstream_conf
" add given content to the end of the response according to the condition specified " add given content to the end of the response according to the condition specified
" https://github.com/flygoast/ngx_http_footer_if_filter " https://github.com/flygoast/ngx_http_footer_if_filter
@@ -2308,6 +2322,62 @@ syn keyword ngxDirectiveThirdParty contained user_agent
" https://github.com/flygoast/ngx_http_upstream_ketama_chash " https://github.com/flygoast/ngx_http_upstream_ketama_chash
syn keyword ngxDirectiveThirdParty contained ketama_chash syn keyword ngxDirectiveThirdParty contained ketama_chash
" nginx-sticky-module-ng
" https://github.com/ayty-adrianomartins/nginx-sticky-module-ng
syn keyword ngxDirectiveThirdParty contained sticky_no_fallback
" dynamic linking and call the function of your application
" https://github.com/Taymindis/nginx-link-function
syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_prop
syn keyword ngxDirectiveThirdParty contained ngx_link_func_add_req_header
syn keyword ngxDirectiveThirdParty contained ngx_link_func_ca_cert
syn keyword ngxDirectiveThirdParty contained ngx_link_func_call
syn keyword ngxDirectiveThirdParty contained ngx_link_func_download_link_lib
syn keyword ngxDirectiveThirdParty contained ngx_link_func_lib
syn keyword ngxDirectiveThirdParty contained ngx_link_func_shm_size
syn keyword ngxDirectiveThirdParty contained ngx_link_func_subrequest
" purge content from FastCGI, proxy, SCGI and uWSGI caches
" https://github.com/torden/ngx_cache_purge
syn keyword ngxDirectiveThirdParty contained cache_purge_response_type
" set the flags "HttpOnly", "secure" and "SameSite" for cookies
" https://github.com/AirisX/nginx_cookie_flag_module
syn keyword ngxDirectiveThirdParty contained set_cookie_flag
" Embed websockify into Nginx (convert any tcp connection into websocket)
" https://github.com/tg123/websockify-nginx-module
syn keyword ngxDirectiveThirdParty contained websockify_buffer_size
syn keyword ngxDirectiveThirdParty contained websockify_connect_timeout
syn keyword ngxDirectiveThirdParty contained websockify_pass
syn keyword ngxDirectiveThirdParty contained websockify_read_timeout
syn keyword ngxDirectiveThirdParty contained websockify_send_timeout
" IP2Location Nginx
" https://github.com/ip2location/ip2location-nginx
syn keyword ngxDirectiveThirdParty contained ip2location
syn keyword ngxDirectiveThirdParty contained ip2location_access_type
syn keyword ngxDirectiveThirdParty contained ip2location_proxy
syn keyword ngxDirectiveThirdParty contained ip2location_proxy_recursive
" IP2Proxy module for Nginx
" https://github.com/ip2location/ip2proxy-nginx
syn keyword ngxDirectiveThirdParty contained ip2proxy
syn keyword ngxDirectiveThirdParty contained ip2proxy_access_type
syn keyword ngxDirectiveThirdParty contained ip2proxy_as
syn keyword ngxDirectiveThirdParty contained ip2proxy_asn
syn keyword ngxDirectiveThirdParty contained ip2proxy_city
syn keyword ngxDirectiveThirdParty contained ip2proxy_country_long
syn keyword ngxDirectiveThirdParty contained ip2proxy_country_short
syn keyword ngxDirectiveThirdParty contained ip2proxy_database
syn keyword ngxDirectiveThirdParty contained ip2proxy_domain
syn keyword ngxDirectiveThirdParty contained ip2proxy_is_proxy
syn keyword ngxDirectiveThirdParty contained ip2proxy_isp
syn keyword ngxDirectiveThirdParty contained ip2proxy_last_seen
syn keyword ngxDirectiveThirdParty contained ip2proxy_proxy_type
syn keyword ngxDirectiveThirdParty contained ip2proxy_region
syn keyword ngxDirectiveThirdParty contained ip2proxy_reverse_proxy
syn keyword ngxDirectiveThirdParty contained ip2proxy_usage_type
+8 -7
View File
@@ -1,5 +1,5 @@
.\" .\"
.\" Copyright (C) 2010 Sergey A. Osokin .\" Copyright (C) 2010, 2019 Sergey A. Osokin
.\" Copyright (C) Nginx, Inc. .\" Copyright (C) Nginx, Inc.
.\" All rights reserved. .\" All rights reserved.
.\" .\"
@@ -25,7 +25,7 @@
.\" SUCH DAMAGE. .\" SUCH DAMAGE.
.\" .\"
.\" .\"
.Dd June 16, 2015 .Dd December 5, 2019
.Dt NGINX 8 .Dt NGINX 8
.Os .Os
.Sh NAME .Sh NAME
@@ -42,7 +42,8 @@
.Nm .Nm
(pronounced (pronounced
.Dq engine x ) .Dq engine x )
is an HTTP and reverse proxy server, as well as a mail proxy server. is an HTTP and reverse proxy server, a mail proxy server, and a generic
TCP/UDP proxy server.
It is known for its high performance, stability, rich feature set, simple It is known for its high performance, stability, rich feature set, simple
configuration, and low resource consumption. configuration, and low resource consumption.
.Pp .Pp
@@ -82,15 +83,15 @@ The following table shows the corresponding system signals:
.It Cm reload .It Cm reload
.Dv SIGHUP .Dv SIGHUP
.El .El
.It Fl T
Same as
.Fl t ,
but additionally dump configuration files to standard output.
.It Fl t .It Fl t
Do not run, just test the configuration file. Do not run, just test the configuration file.
.Nm .Nm
checks the configuration file syntax and then tries to open files checks the configuration file syntax and then tries to open files
referenced in the configuration file. referenced in the configuration file.
.It Fl T
Same as
.Fl t ,
but additionally dump configuration files to standard output.
.It Fl V .It Fl V
Print the Print the
.Nm .Nm
+513
View File
@@ -5,6 +5,519 @@
<change_log title="nginx"> <change_log title="nginx">
<changes ver="1.19.2" date="2020-08-11">
<change type="change">
<para lang="ru">
теперь nginx начинает закрывать keepalive-соединения,
не дожидаясь исчерпания всех свободных соединений,
а также пишет об этом предупреждение в лог ошибок.
</para>
<para lang="en">
now nginx starts closing keepalive connections
before all free worker connections are exhausted,
and logs a warning about this to the error log.
</para>
</change>
<change type="change">
<para lang="ru">
оптимизация чтения тела запроса
при использовании chunked transfer encoding.
</para>
<para lang="en">
optimization of client request body reading
when using chunked transfer encoding.
</para>
</change>
<change type="bugfix">
<para lang="ru">
утечки памяти при использовании директивы ssl_ocsp.
</para>
<para lang="en">
memory leak if the "ssl_ocsp" directive was used.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в логах могли появляться сообщения "zero size buf in output",
если FastCGI-сервер возвращал некорректный ответ;
ошибка появилась в 1.19.1.
</para>
<para lang="en">
"zero size buf in output" alerts might appear in logs
if a FastCGI server returned an incorrect response;
the bug had appeared in 1.19.1.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в рабочем процессе мог произойти segmentation fault,
если размеры large_client_header_buffers отличались
в разных виртуальных серверах.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if different large_client_header_buffers sizes were used
in different virtual servers.
</para>
</change>
<change type="bugfix">
<para lang="ru">
SSL shutdown мог не работать.
</para>
<para lang="en">
SSL shutdown might not work.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в логах могли появляться сообщения
"SSL_shutdown() failed (SSL: ... bad write retry)".
</para>
<para lang="en">
"SSL_shutdown() failed (SSL: ... bad write retry)"
messages might appear in logs.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в модуле ngx_http_slice_module.
</para>
<para lang="en">
in the ngx_http_slice_module.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в модуле ngx_http_xslt_filter_module.
</para>
<para lang="en">
in the ngx_http_xslt_filter_module.
</para>
</change>
</changes>
<changes ver="1.19.1" date="2020-07-07">
<change type="change">
<para lang="ru">
директивы lingering_close, lingering_time и lingering_timeout
теперь работают при использовании HTTP/2.
</para>
<para lang="en">
the "lingering_close", "lingering_time", and "lingering_timeout" directives
now work when using HTTP/2.
</para>
</change>
<change type="change">
<para lang="ru">
теперь лишние данные, присланные бэкендом, всегда отбрасываются.
</para>
<para lang="en">
now extra data sent by a backend are always discarded.
</para>
</change>
<change type="change">
<para lang="ru">
теперь при получении слишком короткого ответа от FastCGI-сервера
nginx пытается отправить клиенту доступную часть ответа,
после чего закрывает соединение с клиентом.
</para>
<para lang="en">
now after receiving a too short response from a FastCGI server
nginx tries to send the available part of the response to the client,
and then closes the client connection.
</para>
</change>
<change type="change">
<para lang="ru">
теперь при получении ответа некорректной длины от gRPC-бэкенда
nginx прекращает обработку ответа с ошибкой.
</para>
<para lang="en">
now after receiving a response with incorrect length from a gRPC backend
nginx stops response processing with an error.
</para>
</change>
<change type="feature">
<para lang="ru">
параметр min_free в директивах proxy_cache_path, fastcgi_cache_path,
scgi_cache_path и uwsgi_cache_path.<br/>
Спасибо Adam Bambuch.
</para>
<para lang="en">
the "min_free" parameter of the "proxy_cache_path", "fastcgi_cache_path",
"scgi_cache_path", and "uwsgi_cache_path" directives.<br/>
Thanks to Adam Bambuch.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не удалял unix domain listen-сокеты
при плавном завершении по сигналу SIGQUIT.
</para>
<para lang="en">
nginx did not delete unix domain listen sockets
during graceful shutdown on the SIGQUIT signal.
</para>
</change>
<change type="bugfix">
<para lang="ru">
UDP-пакеты нулевого размера не проксировались.
</para>
<para lang="en">
zero length UDP datagrams were not proxied.
</para>
</change>
<change type="bugfix">
<para lang="ru">
проксирование на uwsgi-бэкенды с использованием SSL могло не работать.<br/>
Спасибо Guanzhong Chen.
</para>
<para lang="en">
proxying to uwsgi backends using SSL might not work.<br/>
Thanks to Guanzhong Chen.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в обработке ошибок при использовании директивы ssl_ocsp.
</para>
<para lang="en">
in error handling when using the "ssl_ocsp" directive.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании файловых систем XFS и NFS
размер кэша на диске мог считаться некорректно.
</para>
<para lang="en">
on XFS and NFS file systems
disk cache size might be calculated incorrectly.
</para>
</change>
<change type="bugfix">
<para lang="ru">
если сервер memcached возвращал некорректный ответ,
в логах могли появляться сообщения "negative size buf in writer".
</para>
<para lang="en">
"negative size buf in writer" alerts might appear in logs
if a memcached server returned a malformed response.
</para>
</change>
</changes>
<changes ver="1.19.0" date="2020-05-26">
<change type="feature">
<para lang="ru">
проверка клиентских сертификатов с помощью OCSP.
</para>
<para lang="en">
client certificate validation with OCSP.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при работе с gRPC-бэкендами
могли возникать ошибки "upstream sent frame for closed stream".
</para>
<para lang="en">
"upstream sent frame for closed stream" errors might occur
when working with gRPC backends.
</para>
</change>
<change type="bugfix">
<para lang="ru">
OCSP stapling мог не работать,
если не была указана директива resolver.
</para>
<para lang="en">
OCSP stapling might not work
if the "resolver" directive was not specified.
</para>
</change>
<change type="bugfix">
<para lang="ru">
соединения с некорректным HTTP/2 preface не логгировались.
</para>
<para lang="en">
connections with incorrect HTTP/2 preface were not logged.
</para>
</change>
</changes>
<changes ver="1.17.10" date="2020-04-14">
<change type="feature">
<para lang="ru">
директива auth_delay.
</para>
<para lang="en">
the "auth_delay" directive.
</para>
</change>
</changes>
<changes ver="1.17.9" date="2020-03-03">
<change type="change">
<para lang="ru">
теперь nginx не разрешает
несколько строк "Host" в заголовке запроса.
</para>
<para lang="en">
now nginx does not allow
several "Host" request header lines.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx игнорировал дополнительные
строки "Transfer-Encoding" в заголовке запроса.
</para>
<para lang="en">
nginx ignored additional
"Transfer-Encoding" request header lines.
</para>
</change>
<change type="bugfix">
<para lang="ru">
утечки сокетов при использовании HTTP/2.
</para>
<para lang="en">
socket leak when using HTTP/2.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в рабочем процессе мог произойти segmentation fault,
если использовался OCSP stapling.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if OCSP stapling was used.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в модуле ngx_http_mp4_module.
</para>
<para lang="en">
in the ngx_http_mp4_module.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при перенаправлении ошибок с кодом 494 с помощью директивы error_page
nginx возвращал ответ с кодом 494 вместо 400.
</para>
<para lang="en">
nginx used status code 494 instead of 400
if errors with code 494 were redirected with the "error_page" directive.
</para>
</change>
<change type="bugfix">
<para lang="ru">
утечки сокетов при использовании подзапросов в модуле njs и директивы aio.
</para>
<para lang="en">
socket leak when using subrequests in the njs module and the "aio" directive.
</para>
</change>
</changes>
<changes ver="1.17.8" date="2020-01-21">
<change type="feature">
<para lang="ru">
директива grpc_pass поддерживает переменные.
</para>
<para lang="en">
variables support in the "grpc_pass" directive.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при обработке pipelined-запросов по SSL-соединению мог произойти таймаут;
ошибка появилась в 1.17.5.
</para>
<para lang="en">
a timeout might occur while handling pipelined requests in an SSL connection;
the bug had appeared in 1.17.5.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в директиве debug_points при использовании HTTP/2.<br/>
Спасибо Даниилу Бондареву.
</para>
<para lang="en">
in the "debug_points" directive when using HTTP/2.<br/>
Thanks to Daniil Bondarev.
</para>
</change>
</changes>
<changes ver="1.17.7" date="2019-12-24">
<change type="bugfix">
<para lang="ru">
на старте или во время переконфигурации мог произойти segmentation fault,
если в конфигурации использовалась
директива rewrite с пустой строкой замены.
</para>
<para lang="en">
a segmentation fault might occur on start or during reconfiguration
if the "rewrite" directive with an empty replacement string
was used in the configuration.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в рабочем процессе мог произойти segmentation fault,
если директива break использовалась совместно с директивой alias
или директивой proxy_pass с URI.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if the "break" directive was used with the "alias" directive
or with the "proxy_pass" directive with a URI.
</para>
</change>
<change type="bugfix">
<para lang="ru">
строка Location заголовка ответа могла содержать мусор,
если URI запроса был изменён на URI, содержащий нулевой символ.
</para>
<para lang="en">
the "Location" response header line might contain garbage
if the request URI was rewritten to the one containing a null character.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при возврате перенаправлений с помощью директивы error_page
запросы с телом обрабатывались некорректно;
ошибка появилась в 0.7.12.
</para>
<para lang="en">
requests with bodies were handled incorrectly
when returning redirections with the "error_page" directive;
the bug had appeared in 0.7.12.
</para>
</change>
<change type="bugfix">
<para lang="ru">
утечки сокетов при использовании HTTP/2.
</para>
<para lang="en">
socket leak when using HTTP/2.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при обработке pipelined-запросов по SSL-соединению мог произойти таймаут;
ошибка появилась в 1.17.5.
</para>
<para lang="en">
a timeout might occur while handling pipelined requests in an SSL connection;
the bug had appeared in 1.17.5.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в модуле ngx_http_dav_module.
</para>
<para lang="en">
in the ngx_http_dav_module.
</para>
</change>
</changes>
<changes ver="1.17.6" date="2019-11-19">
<change type="feature">
<para lang="ru">
переменные $proxy_protocol_server_addr и $proxy_protocol_server_port.
</para>
<para lang="en">
the $proxy_protocol_server_addr and $proxy_protocol_server_port variables.
</para>
</change>
<change type="feature">
<para lang="ru">
директива limit_conn_dry_run.
</para>
<para lang="en">
the "limit_conn_dry_run" directive.
</para>
</change>
<change type="feature">
<para lang="ru">
переменные $limit_req_status и $limit_conn_status.
</para>
<para lang="en">
the $limit_req_status and $limit_conn_status variables.
</para>
</change>
</changes>
<changes ver="1.17.5" date="2019-10-22"> <changes ver="1.17.5" date="2019-10-22">
<change type="feature"> <change type="feature">
+2 -2
View File
@@ -6,9 +6,9 @@ TEMP = tmp
CC = cl CC = cl
OBJS = objs.msvc8 OBJS = objs.msvc8
OPENSSL = openssl-1.1.1d OPENSSL = openssl-1.1.1g
ZLIB = zlib-1.2.11 ZLIB = zlib-1.2.11
PCRE = pcre-8.43 PCRE = pcre-8.44
release: export release: export
+1
View File
@@ -492,6 +492,7 @@ ngx_add_inherited_sockets(ngx_cycle_t *cycle)
ngx_memzero(ls, sizeof(ngx_listening_t)); ngx_memzero(ls, sizeof(ngx_listening_t));
ls->fd = (ngx_socket_t) s; ls->fd = (ngx_socket_t) s;
ls->inherited = 1;
} }
} }
+2 -2
View File
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_ #define _NGINX_H_INCLUDED_
#define nginx_version 1017006 #define nginx_version 1019003
#define NGINX_VERSION "1.17.6" #define NGINX_VERSION "1.19.3"
#define NGINX_VER "nginx/" NGINX_VERSION " by Hakase" #define NGINX_VER "nginx/" NGINX_VERSION " by Hakase"
#ifndef NGINX_SERVER #ifndef NGINX_SERVER
+10 -10
View File
@@ -125,20 +125,20 @@ typedef struct {
#define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR #define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR
#define ngx_buf_in_memory(b) (b->temporary || b->memory || b->mmap) #define ngx_buf_in_memory(b) ((b)->temporary || (b)->memory || (b)->mmap)
#define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !b->in_file) #define ngx_buf_in_memory_only(b) (ngx_buf_in_memory(b) && !(b)->in_file)
#define ngx_buf_special(b) \ #define ngx_buf_special(b) \
((b->flush || b->last_buf || b->sync) \ (((b)->flush || (b)->last_buf || (b)->sync) \
&& !ngx_buf_in_memory(b) && !b->in_file) && !ngx_buf_in_memory(b) && !(b)->in_file)
#define ngx_buf_sync_only(b) \ #define ngx_buf_sync_only(b) \
(b->sync \ ((b)->sync && !ngx_buf_in_memory(b) \
&& !ngx_buf_in_memory(b) && !b->in_file && !b->flush && !b->last_buf) && !(b)->in_file && !(b)->flush && !(b)->last_buf)
#define ngx_buf_size(b) \ #define ngx_buf_size(b) \
(ngx_buf_in_memory(b) ? (off_t) (b->last - b->pos): \ (ngx_buf_in_memory(b) ? (off_t) ((b)->last - (b)->pos): \
(b->file_last - b->file_pos)) ((b)->file_last - (b)->file_pos))
ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size); ngx_buf_t *ngx_create_temp_buf(ngx_pool_t *pool, size_t size);
ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs); ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
@@ -149,8 +149,8 @@ ngx_chain_t *ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs);
ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool); ngx_chain_t *ngx_alloc_chain_link(ngx_pool_t *pool);
#define ngx_free_chain(pool, cl) \ #define ngx_free_chain(pool, cl) \
cl->next = pool->chain; \ (cl)->next = (pool)->chain; \
pool->chain = cl (pool)->chain = (cl)
+19 -6
View File
@@ -1070,7 +1070,8 @@ ngx_close_listening_sockets(ngx_cycle_t *cycle)
if (ls[i].sockaddr->sa_family == AF_UNIX if (ls[i].sockaddr->sa_family == AF_UNIX
&& ngx_process <= NGX_PROCESS_MASTER && ngx_process <= NGX_PROCESS_MASTER
&& ngx_new_binary == 0) && ngx_new_binary == 0
&& (!ls[i].inherited || ngx_getppid() != ngx_parent))
{ {
u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1;
@@ -1106,12 +1107,9 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
return NULL; return NULL;
} }
c = ngx_cycle->free_connections; ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
if (c == NULL) { c = ngx_cycle->free_connections;
ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
c = ngx_cycle->free_connections;
}
if (c == NULL) { if (c == NULL) {
ngx_log_error(NGX_LOG_ALERT, log, 0, ngx_log_error(NGX_LOG_ALERT, log, 0,
@@ -1297,6 +1295,21 @@ ngx_drain_connections(ngx_cycle_t *cycle)
ngx_queue_t *q; ngx_queue_t *q;
ngx_connection_t *c; ngx_connection_t *c;
if (cycle->free_connection_n > cycle->connection_n / 16
|| cycle->reusable_connections_n == 0)
{
return;
}
if (cycle->connections_reuse_time != ngx_time()) {
cycle->connections_reuse_time = ngx_time();
ngx_log_error(NGX_LOG_WARN, cycle->log, 0,
"%ui worker_connections are not enough, "
"reusing connections",
cycle->connection_n);
}
n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1); n = ngx_max(ngx_min(32, cycle->reusable_connections_n / 8), 1);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
+6 -2
View File
@@ -520,6 +520,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
== NGX_OK) == NGX_OK)
{ {
nls[n].fd = ls[i].fd; nls[n].fd = ls[i].fd;
nls[n].inherited = ls[i].inherited;
nls[n].previous = &ls[i]; nls[n].previous = &ls[i];
ls[i].remain = 1; ls[i].remain = 1;
@@ -1008,6 +1009,7 @@ ngx_int_t
ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
{ {
size_t len; size_t len;
ngx_int_t rc;
ngx_uint_t create; ngx_uint_t create;
ngx_file_t file; ngx_file_t file;
u_char pid[NGX_INT64_LEN + 2]; u_char pid[NGX_INT64_LEN + 2];
@@ -1032,11 +1034,13 @@ ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
return NGX_ERROR; return NGX_ERROR;
} }
rc = NGX_OK;
if (!ngx_test_config) { if (!ngx_test_config) {
len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid; len = ngx_snprintf(pid, NGX_INT64_LEN + 2, "%P%N", ngx_pid) - pid;
if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) { if (ngx_write_file(&file, pid, len, 0) == NGX_ERROR) {
return NGX_ERROR; rc = NGX_ERROR;
} }
} }
@@ -1045,7 +1049,7 @@ ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
ngx_close_file_n " \"%s\" failed", file.name.data); ngx_close_file_n " \"%s\" failed", file.name.data);
} }
return NGX_OK; return rc;
} }
+1
View File
@@ -55,6 +55,7 @@ struct ngx_cycle_s {
ngx_queue_t reusable_connections_queue; ngx_queue_t reusable_connections_queue;
ngx_uint_t reusable_connections_n; ngx_uint_t reusable_connections_n;
time_t connections_reuse_time;
ngx_array_t listening; ngx_array_t listening;
ngx_array_t paths; ngx_array_t paths;
+1 -2
View File
@@ -238,8 +238,7 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle)
} }
if (!ngx_queue_empty(&ngx_posted_next_events)) { if (!ngx_queue_empty(&ngx_posted_next_events)) {
ngx_queue_add(&ngx_posted_events, &ngx_posted_next_events); ngx_event_move_posted_next(cycle);
ngx_queue_init(&ngx_posted_next_events);
timer = 0; timer = 0;
} }
+111 -74
View File
@@ -43,7 +43,6 @@ static ssize_t ngx_ssl_recv_early(ngx_connection_t *c, u_char *buf,
#endif #endif
static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
static void ngx_ssl_write_handler(ngx_event_t *wev); static void ngx_ssl_write_handler(ngx_event_t *wev);
static void ngx_ssl_next_read_handler(ngx_event_t *rev);
#ifdef SSL_READ_EARLY_DATA_SUCCESS #ifdef SSL_READ_EARLY_DATA_SUCCESS
static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data, static ssize_t ngx_ssl_write_early(ngx_connection_t *c, u_char *data,
size_t size); size_t size);
@@ -131,6 +130,7 @@ int ngx_ssl_connection_index;
int ngx_ssl_server_conf_index; int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index; int ngx_ssl_session_cache_index;
int ngx_ssl_session_ticket_keys_index; int ngx_ssl_session_ticket_keys_index;
int ngx_ssl_ocsp_index;
int ngx_ssl_certificate_index; int ngx_ssl_certificate_index;
int ngx_ssl_next_certificate_index; int ngx_ssl_next_certificate_index;
int ngx_ssl_certificate_name_index; int ngx_ssl_certificate_name_index;
@@ -214,6 +214,13 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR; return NGX_ERROR;
} }
ngx_ssl_ocsp_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
if (ngx_ssl_ocsp_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0,
"SSL_CTX_get_ex_new_index() failed");
return NGX_ERROR;
}
ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
NULL); NULL);
if (ngx_ssl_certificate_index == -1) { if (ngx_ssl_certificate_index == -1) {
@@ -921,6 +928,9 @@ ngx_int_t
ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_int_t depth) ngx_int_t depth)
{ {
SSL_CTX_set_verify(ssl->ctx, SSL_CTX_get_verify_mode(ssl->ctx),
ngx_ssl_verify_callback);
SSL_CTX_set_verify_depth(ssl->ctx, depth); SSL_CTX_set_verify_depth(ssl->ctx, depth);
if (cert->len == 0) { if (cert->len == 0) {
@@ -1604,6 +1614,7 @@ ngx_ssl_handshake(ngx_connection_t *c)
{ {
int n, sslerr; int n, sslerr;
ngx_err_t err; ngx_err_t err;
ngx_int_t rc;
#ifdef SSL_READ_EARLY_DATA_SUCCESS #ifdef SSL_READ_EARLY_DATA_SUCCESS
if (c->ssl->try_early_data) { if (c->ssl->try_early_data) {
@@ -1611,6 +1622,10 @@ ngx_ssl_handshake(ngx_connection_t *c)
} }
#endif #endif
if (c->ssl->in_ocsp) {
return ngx_ssl_ocsp_validate(c);
}
ngx_ssl_clear_error(c->log); ngx_ssl_clear_error(c->log);
n = SSL_do_handshake(c->ssl->connection); n = SSL_do_handshake(c->ssl->connection);
@@ -1631,8 +1646,6 @@ ngx_ssl_handshake(ngx_connection_t *c)
ngx_ssl_handshake_log(c); ngx_ssl_handshake_log(c);
#endif #endif
c->ssl->handshaked = 1;
c->recv = ngx_ssl_recv; c->recv = ngx_ssl_recv;
c->send = ngx_ssl_write; c->send = ngx_ssl_write;
c->recv_chain = ngx_ssl_recv_chain; c->recv_chain = ngx_ssl_recv_chain;
@@ -1651,6 +1664,20 @@ ngx_ssl_handshake(ngx_connection_t *c)
#endif #endif
#endif #endif
rc = ngx_ssl_ocsp_validate(c);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_AGAIN) {
c->read->handler = ngx_ssl_handshake_handler;
c->write->handler = ngx_ssl_handshake_handler;
return NGX_AGAIN;
}
c->ssl->handshaked = 1;
return NGX_OK; return NGX_OK;
} }
@@ -1720,6 +1747,7 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
u_char buf; u_char buf;
size_t readbytes; size_t readbytes;
ngx_err_t err; ngx_err_t err;
ngx_int_t rc;
ngx_ssl_clear_error(c->log); ngx_ssl_clear_error(c->log);
@@ -1754,7 +1782,6 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
c->ssl->early_buf = buf; c->ssl->early_buf = buf;
c->ssl->early_preread = 1; c->ssl->early_preread = 1;
c->ssl->handshaked = 1;
c->ssl->in_early = 1; c->ssl->in_early = 1;
c->recv = ngx_ssl_recv; c->recv = ngx_ssl_recv;
@@ -1762,6 +1789,20 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
c->recv_chain = ngx_ssl_recv_chain; c->recv_chain = ngx_ssl_recv_chain;
c->send_chain = ngx_ssl_send_chain; c->send_chain = ngx_ssl_send_chain;
rc = ngx_ssl_ocsp_validate(c);
if (rc == NGX_ERROR) {
return NGX_ERROR;
}
if (rc == NGX_AGAIN) {
c->read->handler = ngx_ssl_handshake_handler;
c->write->handler = ngx_ssl_handshake_handler;
return NGX_AGAIN;
}
c->ssl->handshaked = 1;
return NGX_OK; return NGX_OK;
} }
@@ -2027,9 +2068,8 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
c->read->available = 0; c->read->available = 0;
c->read->ready = 0; c->read->ready = 0;
if (c->ssl->next_read_handler == NULL) { if (c->read->posted) {
c->ssl->next_read_handler = c->read->handler; ngx_delete_posted_event(c->read);
c->read->handler = ngx_ssl_next_read_handler;
} }
ngx_post_event(c->read, &ngx_posted_next_events); ngx_post_event(c->read, &ngx_posted_next_events);
@@ -2337,31 +2377,6 @@ ngx_ssl_write_handler(ngx_event_t *wev)
} }
static void
ngx_ssl_next_read_handler(ngx_event_t *rev)
{
ngx_connection_t *c;
c = rev->data;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL next read handler");
rev->handler = c->ssl->next_read_handler;
c->ssl->next_read_handler = NULL;
if (!rev->ready) {
rev->ready = 1;
rev->available = -1;
}
if (rev->posted) {
ngx_delete_posted_event(rev);
}
rev->handler(rev);
}
/* /*
* OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
* before the SSL_write() call to decrease a SSL overhead. * before the SSL_write() call to decrease a SSL overhead.
@@ -2806,8 +2821,11 @@ ngx_ssl_free_buffer(ngx_connection_t *c)
ngx_int_t ngx_int_t
ngx_ssl_shutdown(ngx_connection_t *c) ngx_ssl_shutdown(ngx_connection_t *c)
{ {
int n, sslerr, mode; int n, sslerr, mode;
ngx_err_t err; ngx_err_t err;
ngx_uint_t tries;
ngx_ssl_ocsp_cleanup(c);
if (SSL_in_init(c->ssl->connection)) { if (SSL_in_init(c->ssl->connection)) {
/* /*
@@ -2846,55 +2864,71 @@ ngx_ssl_shutdown(ngx_connection_t *c)
ngx_ssl_clear_error(c->log); ngx_ssl_clear_error(c->log);
n = SSL_shutdown(c->ssl->connection); tries = 2;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); for ( ;; ) {
sslerr = 0; /*
* For bidirectional shutdown, SSL_shutdown() needs to be called
* twice: first call sends the "close notify" alert and returns 0,
* second call waits for the peer's "close notify" alert.
*/
/* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */ n = SSL_shutdown(c->ssl->connection);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
if (n == 1) {
SSL_free(c->ssl->connection);
c->ssl = NULL;
return NGX_OK;
}
if (n == 0 && tries-- > 1) {
continue;
}
/* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */
if (n != 1 && ERR_peek_error()) {
sslerr = SSL_get_error(c->ssl->connection, n); sslerr = SSL_get_error(c->ssl->connection, n);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_get_error: %d", sslerr); "SSL_get_error: %d", sslerr);
}
if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) { if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
c->read->handler = ngx_ssl_shutdown_handler;
c->write->handler = ngx_ssl_shutdown_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;
}
ngx_add_timer(c->read, 3000);
return NGX_AGAIN;
}
if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
SSL_free(c->ssl->connection);
c->ssl = NULL;
return NGX_OK;
}
err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
SSL_free(c->ssl->connection); SSL_free(c->ssl->connection);
c->ssl = NULL; c->ssl = NULL;
return NGX_OK; return NGX_ERROR;
} }
if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
c->read->handler = ngx_ssl_shutdown_handler;
c->write->handler = ngx_ssl_shutdown_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;
}
if (sslerr == SSL_ERROR_WANT_READ) {
ngx_add_timer(c->read, 30000);
}
return NGX_AGAIN;
}
err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
SSL_free(c->ssl->connection);
c->ssl = NULL;
return NGX_ERROR;
} }
@@ -4990,11 +5024,14 @@ ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
rc = SSL_get_verify_result(c->ssl->connection); rc = SSL_get_verify_result(c->ssl->connection);
if (rc == X509_V_OK) { if (rc == X509_V_OK) {
ngx_str_set(s, "SUCCESS"); if (ngx_ssl_ocsp_get_status(c, &str) == NGX_OK) {
return NGX_OK; ngx_str_set(s, "SUCCESS");
} return NGX_OK;
}
str = X509_verify_cert_error_string(rc); } else {
str = X509_verify_cert_error_string(rc);
}
s->data = ngx_pnalloc(pool, sizeof("FAILED:") - 1 + ngx_strlen(str)); s->data = ngx_pnalloc(pool, sizeof("FAILED:") - 1 + ngx_strlen(str));
if (s->data == NULL) { if (s->data == NULL) {
+15 -1
View File
@@ -72,6 +72,9 @@ typedef struct {
} ngx_ssl_dyn_rec_t; } ngx_ssl_dyn_rec_t;
typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t;
struct ngx_ssl_s { struct ngx_ssl_s {
SSL_CTX *ctx; SSL_CTX *ctx;
ngx_log_t *log; ngx_log_t *log;
@@ -95,7 +98,8 @@ struct ngx_ssl_connection_s {
ngx_event_handler_pt saved_read_handler; ngx_event_handler_pt saved_read_handler;
ngx_event_handler_pt saved_write_handler; ngx_event_handler_pt saved_write_handler;
ngx_event_handler_pt next_read_handler;
ngx_ssl_ocsp_t *ocsp;
u_char early_buf; u_char early_buf;
@@ -107,6 +111,7 @@ struct ngx_ssl_connection_s {
unsigned handshake_buffer_set:1; unsigned handshake_buffer_set:1;
unsigned try_early_data:1; unsigned try_early_data:1;
unsigned in_early:1; unsigned in_early:1;
unsigned in_ocsp:1;
unsigned early_preread:1; unsigned early_preread:1;
unsigned write_blocked:1; unsigned write_blocked:1;
@@ -194,6 +199,14 @@ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify); ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);
ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout); ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
ngx_int_t ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder,
ngx_uint_t depth, ngx_shm_zone_t *shm_zone);
ngx_int_t ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c);
ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s);
void ngx_ssl_ocsp_cleanup(ngx_connection_t *c);
ngx_int_t ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data);
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export, RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
int key_length); int key_length);
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file); ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
@@ -295,6 +308,7 @@ extern int ngx_ssl_connection_index;
extern int ngx_ssl_server_conf_index; extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index; extern int ngx_ssl_session_cache_index;
extern int ngx_ssl_session_ticket_keys_index; extern int ngx_ssl_session_ticket_keys_index;
extern int ngx_ssl_ocsp_index;
extern int ngx_ssl_certificate_index; extern int ngx_ssl_certificate_index;
extern int ngx_ssl_next_certificate_index; extern int ngx_ssl_next_certificate_index;
extern int ngx_ssl_certificate_name_index; extern int ngx_ssl_certificate_name_index;
+1065 -173
View File
@@ -22,6 +22,7 @@ typedef struct {
ngx_msec_t resolver_timeout; ngx_msec_t resolver_timeout;
ngx_addr_t *addrs; ngx_addr_t *addrs;
ngx_uint_t naddrs;
ngx_str_t host; ngx_str_t host;
ngx_str_t uri; ngx_str_t uri;
in_port_t port; in_port_t port;
@@ -30,6 +31,7 @@ typedef struct {
X509 *cert; X509 *cert;
X509 *issuer; X509 *issuer;
STACK_OF(X509) *chain;
u_char *name; u_char *name;
@@ -41,15 +43,66 @@ typedef struct {
} ngx_ssl_stapling_t; } ngx_ssl_stapling_t;
typedef struct {
ngx_addr_t *addrs;
ngx_uint_t naddrs;
ngx_str_t host;
ngx_str_t uri;
in_port_t port;
ngx_uint_t depth;
ngx_shm_zone_t *shm_zone;
ngx_resolver_t *resolver;
ngx_msec_t resolver_timeout;
} ngx_ssl_ocsp_conf_t;
typedef struct {
ngx_rbtree_t rbtree;
ngx_rbtree_node_t sentinel;
ngx_queue_t expire_queue;
} ngx_ssl_ocsp_cache_t;
typedef struct {
ngx_str_node_t node;
ngx_queue_t queue;
int status;
time_t valid;
} ngx_ssl_ocsp_cache_node_t;
typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t; typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t;
struct ngx_ssl_ocsp_s {
STACK_OF(X509) *certs;
ngx_uint_t ncert;
int cert_status;
ngx_int_t status;
ngx_ssl_ocsp_conf_t *conf;
ngx_ssl_ocsp_ctx_t *ctx;
};
struct ngx_ssl_ocsp_ctx_s { struct ngx_ssl_ocsp_ctx_s {
SSL_CTX *ssl_ctx;
X509 *cert; X509 *cert;
X509 *issuer; X509 *issuer;
STACK_OF(X509) *chain;
int status;
time_t valid;
u_char *name; u_char *name;
ngx_uint_t naddrs; ngx_uint_t naddrs;
ngx_uint_t naddr;
ngx_addr_t *addrs; ngx_addr_t *addrs;
ngx_str_t host; ngx_str_t host;
@@ -64,17 +117,20 @@ struct ngx_ssl_ocsp_ctx_s {
void (*handler)(ngx_ssl_ocsp_ctx_t *ctx); void (*handler)(ngx_ssl_ocsp_ctx_t *ctx);
void *data; void *data;
ngx_str_t key;
ngx_buf_t *request; ngx_buf_t *request;
ngx_buf_t *response; ngx_buf_t *response;
ngx_peer_connection_t peer; ngx_peer_connection_t peer;
ngx_shm_zone_t *shm_zone;
ngx_int_t (*process)(ngx_ssl_ocsp_ctx_t *ctx); ngx_int_t (*process)(ngx_ssl_ocsp_ctx_t *ctx);
ngx_uint_t state; ngx_uint_t state;
ngx_uint_t code; ngx_uint_t code;
ngx_uint_t count; ngx_uint_t count;
ngx_uint_t flags;
ngx_uint_t done; ngx_uint_t done;
u_char *header_name_start; u_char *header_name_start;
@@ -105,8 +161,14 @@ static time_t ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time);
static void ngx_ssl_stapling_cleanup(void *data); static void ngx_ssl_stapling_cleanup(void *data);
static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void); static void ngx_ssl_ocsp_validate_next(ngx_connection_t *c);
static void ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_responder(ngx_connection_t *c,
ngx_ssl_ocsp_ctx_t *ctx);
static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(ngx_log_t *log);
static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx); static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx);
static void ngx_ssl_ocsp_next(ngx_ssl_ocsp_ctx_t *ctx);
static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx); static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx);
static void ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve); static void ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve);
static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx); static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx);
@@ -120,6 +182,11 @@ static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx); static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx); static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx); static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_verify(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_cache_lookup(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_cache_store(ngx_ssl_ocsp_ctx_t *ctx);
static ngx_int_t ngx_ssl_ocsp_create_key(ngx_ssl_ocsp_ctx_t *ctx);
static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len); static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len);
@@ -173,6 +240,18 @@ ngx_ssl_stapling_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, X509 *cert,
return NGX_ERROR; return NGX_ERROR;
} }
#ifdef SSL_CTRL_SELECT_CURRENT_CERT
/* OpenSSL 1.0.2+ */
SSL_CTX_select_current_cert(ssl->ctx, cert);
#endif
#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS
/* OpenSSL 1.0.1+ */
SSL_CTX_get_extra_chain_certs(ssl->ctx, &staple->chain);
#else
staple->chain = ssl->ctx->extra_certs;
#endif
staple->ssl_ctx = ssl->ctx; staple->ssl_ctx = ssl->ctx;
staple->timeout = 60000; staple->timeout = 60000;
staple->verify = verify; staple->verify = verify;
@@ -289,29 +368,16 @@ ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl,
X509 *cert, *issuer; X509 *cert, *issuer;
X509_STORE *store; X509_STORE *store;
X509_STORE_CTX *store_ctx; X509_STORE_CTX *store_ctx;
STACK_OF(X509) *chain;
cert = staple->cert; cert = staple->cert;
#ifdef SSL_CTRL_SELECT_CURRENT_CERT n = sk_X509_num(staple->chain);
/* OpenSSL 1.0.2+ */
SSL_CTX_select_current_cert(ssl->ctx, cert);
#endif
#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS
/* OpenSSL 1.0.1+ */
SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
#else
chain = ssl->ctx->extra_certs;
#endif
n = sk_X509_num(chain);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
"SSL get issuer: %d extra certs", n); "SSL get issuer: %d extra certs", n);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
issuer = sk_X509_value(chain, i); issuer = sk_X509_value(staple->chain, i);
if (X509_check_issued(issuer, cert) == X509_V_OK) { if (X509_check_issued(issuer, cert) == X509_V_OK) {
#if OPENSSL_VERSION_NUMBER >= 0x10100001L #if OPENSSL_VERSION_NUMBER >= 0x10100001L
X509_up_ref(issuer); X509_up_ref(issuer);
@@ -462,6 +528,7 @@ ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
} }
staple->addrs = u.addrs; staple->addrs = u.addrs;
staple->naddrs = u.naddrs;
staple->host = u.host; staple->host = u.host;
staple->uri = u.uri; staple->uri = u.uri;
staple->port = u.port; staple->port = u.port;
@@ -559,16 +626,20 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
staple->loading = 1; staple->loading = 1;
ctx = ngx_ssl_ocsp_start(); ctx = ngx_ssl_ocsp_start(ngx_cycle->log);
if (ctx == NULL) { if (ctx == NULL) {
return; return;
} }
ctx->ssl_ctx = staple->ssl_ctx;
ctx->cert = staple->cert; ctx->cert = staple->cert;
ctx->issuer = staple->issuer; ctx->issuer = staple->issuer;
ctx->chain = staple->chain;
ctx->name = staple->name; ctx->name = staple->name;
ctx->flags = (staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY);
ctx->addrs = staple->addrs; ctx->addrs = staple->addrs;
ctx->naddrs = staple->naddrs;
ctx->host = staple->host; ctx->host = staple->host;
ctx->uri = staple->uri; ctx->uri = staple->uri;
ctx->port = staple->port; ctx->port = staple->port;
@@ -589,137 +660,27 @@ ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
static void static void
ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
{ {
int n; time_t now;
size_t len; ngx_str_t response;
time_t now, valid; ngx_ssl_stapling_t *staple;
ngx_str_t response;
X509_STORE *store;
const u_char *p;
STACK_OF(X509) *chain;
OCSP_CERTID *id;
OCSP_RESPONSE *ocsp;
OCSP_BASICRESP *basic;
ngx_ssl_stapling_t *staple;
ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;
staple = ctx->data; staple = ctx->data;
now = ngx_time(); now = ngx_time();
ocsp = NULL;
basic = NULL;
id = NULL;
if (ctx->code != 200) { if (ngx_ssl_ocsp_verify(ctx) != NGX_OK) {
goto error; goto error;
} }
/* check the response */ if (ctx->status != V_OCSP_CERTSTATUS_GOOD) {
len = ctx->response->last - ctx->response->pos;
p = ctx->response->pos;
ocsp = d2i_OCSP_RESPONSE(NULL, &p, len);
if (ocsp == NULL) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"d2i_OCSP_RESPONSE() failed");
goto error;
}
n = OCSP_response_status(ocsp);
if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP response not successful (%d: %s)",
n, OCSP_response_status_str(n));
goto error;
}
basic = OCSP_response_get1_basic(ocsp);
if (basic == NULL) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_response_get1_basic() failed");
goto error;
}
store = SSL_CTX_get_cert_store(staple->ssl_ctx);
if (store == NULL) {
ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
"SSL_CTX_get_cert_store() failed");
goto error;
}
#ifdef SSL_CTRL_SELECT_CURRENT_CERT
/* OpenSSL 1.0.2+ */
SSL_CTX_select_current_cert(staple->ssl_ctx, ctx->cert);
#endif
#ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS
/* OpenSSL 1.0.1+ */
SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
#else
chain = staple->ssl_ctx->extra_certs;
#endif
if (OCSP_basic_verify(basic, chain, store,
staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)
!= 1)
{
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_basic_verify() failed");
goto error;
}
id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
if (id == NULL) {
ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
"OCSP_cert_to_id() failed");
goto error;
}
if (OCSP_resp_find_status(basic, id, &n, NULL, NULL,
&thisupdate, &nextupdate)
!= 1)
{
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"certificate status not found in the OCSP response");
goto error;
}
if (n != V_OCSP_CERTSTATUS_GOOD) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0, ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"certificate status \"%s\" in the OCSP response", "certificate status \"%s\" in the OCSP response",
OCSP_cert_status_str(n)); OCSP_cert_status_str(ctx->status));
goto error; goto error;
} }
if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_check_validity() failed");
goto error;
}
if (nextupdate) {
valid = ngx_ssl_stapling_time(nextupdate);
if (valid == (time_t) NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"invalid nextUpdate time in certificate status");
goto error;
}
} else {
valid = NGX_MAX_TIME_T_VALUE;
}
OCSP_CERTID_free(id);
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(ocsp);
id = NULL;
basic = NULL;
ocsp = NULL;
/* copy the response to memory not in ctx->pool */ /* copy the response to memory not in ctx->pool */
response.len = len; response.len = ctx->response->last - ctx->response->pos;
response.data = ngx_alloc(response.len, ctx->log); response.data = ngx_alloc(response.len, ctx->log);
if (response.data == NULL) { if (response.data == NULL) {
@@ -728,16 +689,12 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
ngx_memcpy(response.data, ctx->response->pos, response.len); ngx_memcpy(response.data, ctx->response->pos, response.len);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp response, %s, %uz",
OCSP_cert_status_str(n), response.len);
if (staple->staple.data) { if (staple->staple.data) {
ngx_free(staple->staple.data); ngx_free(staple->staple.data);
} }
staple->staple = response; staple->staple = response;
staple->valid = valid; staple->valid = ctx->valid;
/* /*
* refresh before the response expires, * refresh before the response expires,
@@ -745,7 +702,7 @@ ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
*/ */
staple->loading = 0; staple->loading = 0;
staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); staple->refresh = ngx_max(ngx_min(ctx->valid - 300, now + 3600), now + 300);
ngx_ssl_ocsp_done(ctx); ngx_ssl_ocsp_done(ctx);
return; return;
@@ -755,18 +712,6 @@ error:
staple->loading = 0; staple->loading = 0;
staple->refresh = now + 300; staple->refresh = now + 300;
if (id) {
OCSP_CERTID_free(id);
}
if (basic) {
OCSP_BASICRESP_free(basic);
}
if (ocsp) {
OCSP_RESPONSE_free(ocsp);
}
ngx_ssl_ocsp_done(ctx); ngx_ssl_ocsp_done(ctx);
} }
@@ -820,14 +765,507 @@ ngx_ssl_stapling_cleanup(void *data)
} }
static ngx_ssl_ocsp_ctx_t * ngx_int_t
ngx_ssl_ocsp_start(void) ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder,
ngx_uint_t depth, ngx_shm_zone_t *shm_zone)
{
ngx_url_t u;
ngx_ssl_ocsp_conf_t *ocf;
ocf = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_ocsp_conf_t));
if (ocf == NULL) {
return NGX_ERROR;
}
ocf->depth = depth;
ocf->shm_zone = shm_zone;
if (responder->len) {
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = *responder;
u.default_port = 80;
u.uri_part = 1;
if (u.url.len > 7
&& ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0)
{
u.url.len -= 7;
u.url.data += 7;
} else {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"invalid URL prefix in OCSP responder \"%V\" "
"in \"ssl_ocsp_responder\"", &u.url);
return NGX_ERROR;
}
if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
if (u.err) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"%s in OCSP responder \"%V\" "
"in \"ssl_ocsp_responder\"", u.err, &u.url);
}
return NGX_ERROR;
}
ocf->addrs = u.addrs;
ocf->naddrs = u.naddrs;
ocf->host = u.host;
ocf->uri = u.uri;
ocf->port = u.port;
}
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_ocsp_index, ocf) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"SSL_CTX_set_ex_data() failed");
return NGX_ERROR;
}
return NGX_OK;
}
ngx_int_t
ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
{
ngx_ssl_ocsp_conf_t *ocf;
ocf = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_ocsp_index);
ocf->resolver = resolver;
ocf->resolver_timeout = resolver_timeout;
return NGX_OK;
}
ngx_int_t
ngx_ssl_ocsp_validate(ngx_connection_t *c)
{
X509 *cert;
SSL_CTX *ssl_ctx;
ngx_int_t rc;
X509_STORE *store;
X509_STORE_CTX *store_ctx;
STACK_OF(X509) *chain;
ngx_ssl_ocsp_t *ocsp;
ngx_ssl_ocsp_conf_t *ocf;
if (c->ssl->in_ocsp) {
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;
}
ssl_ctx = SSL_get_SSL_CTX(c->ssl->connection);
ocf = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_ocsp_index);
if (ocf == NULL) {
return NGX_OK;
}
if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
return NGX_OK;
}
cert = SSL_get_peer_certificate(c->ssl->connection);
if (cert == NULL) {
return NGX_OK;
}
ocsp = ngx_pcalloc(c->pool, sizeof(ngx_ssl_ocsp_t));
if (ocsp == NULL) {
X509_free(cert);
return NGX_ERROR;
}
c->ssl->ocsp = ocsp;
ocsp->status = NGX_AGAIN;
ocsp->cert_status = V_OCSP_CERTSTATUS_GOOD;
ocsp->conf = ocf;
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined LIBRESSL_VERSION_NUMBER)
ocsp->certs = SSL_get0_verified_chain(c->ssl->connection);
if (ocsp->certs) {
ocsp->certs = X509_chain_up_ref(ocsp->certs);
if (ocsp->certs == NULL) {
X509_free(cert);
return NGX_ERROR;
}
}
#endif
if (ocsp->certs == NULL) {
store = SSL_CTX_get_cert_store(ssl_ctx);
if (store == NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"SSL_CTX_get_cert_store() failed");
X509_free(cert);
return NGX_ERROR;
}
store_ctx = X509_STORE_CTX_new();
if (store_ctx == NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"X509_STORE_CTX_new() failed");
X509_free(cert);
return NGX_ERROR;
}
chain = SSL_get_peer_cert_chain(c->ssl->connection);
if (X509_STORE_CTX_init(store_ctx, store, cert, chain) == 0) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"X509_STORE_CTX_init() failed");
X509_STORE_CTX_free(store_ctx);
X509_free(cert);
return NGX_ERROR;
}
rc = X509_verify_cert(store_ctx);
if (rc <= 0) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "X509_verify_cert() failed");
X509_STORE_CTX_free(store_ctx);
X509_free(cert);
return NGX_ERROR;
}
ocsp->certs = X509_STORE_CTX_get1_chain(store_ctx);
if (ocsp->certs == NULL) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"X509_STORE_CTX_get1_chain() failed");
X509_STORE_CTX_free(store_ctx);
X509_free(cert);
return NGX_ERROR;
}
X509_STORE_CTX_free(store_ctx);
}
X509_free(cert);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ssl ocsp validate, certs:%d", sk_X509_num(ocsp->certs));
ngx_ssl_ocsp_validate_next(c);
if (ocsp->status == NGX_AGAIN) {
c->ssl->in_ocsp = 1;
return NGX_AGAIN;
}
return NGX_OK;
}
static void
ngx_ssl_ocsp_validate_next(ngx_connection_t *c)
{
ngx_int_t rc;
ngx_uint_t n;
ngx_ssl_ocsp_t *ocsp;
ngx_ssl_ocsp_ctx_t *ctx;
ngx_ssl_ocsp_conf_t *ocf;
ocsp = c->ssl->ocsp;
ocf = ocsp->conf;
n = sk_X509_num(ocsp->certs);
for ( ;; ) {
if (ocsp->ncert == n - 1 || (ocf->depth == 2 && ocsp->ncert == 1)) {
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ssl ocsp validated, certs:%ui", ocsp->ncert);
rc = NGX_OK;
goto done;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ssl ocsp validate cert:%ui", ocsp->ncert);
ctx = ngx_ssl_ocsp_start(c->log);
if (ctx == NULL) {
rc = NGX_ERROR;
goto done;
}
ocsp->ctx = ctx;
ctx->ssl_ctx = SSL_get_SSL_CTX(c->ssl->connection);
ctx->cert = sk_X509_value(ocsp->certs, ocsp->ncert);
ctx->issuer = sk_X509_value(ocsp->certs, ocsp->ncert + 1);
ctx->chain = ocsp->certs;
ctx->resolver = ocf->resolver;
ctx->resolver_timeout = ocf->resolver_timeout;
ctx->handler = ngx_ssl_ocsp_handler;
ctx->data = c;
ctx->shm_zone = ocf->shm_zone;
ctx->addrs = ocf->addrs;
ctx->naddrs = ocf->naddrs;
ctx->host = ocf->host;
ctx->uri = ocf->uri;
ctx->port = ocf->port;
rc = ngx_ssl_ocsp_responder(c, ctx);
if (rc != NGX_OK) {
goto done;
}
if (ctx->uri.len == 0) {
ngx_str_set(&ctx->uri, "/");
}
ocsp->ncert++;
rc = ngx_ssl_ocsp_cache_lookup(ctx);
if (rc == NGX_ERROR) {
goto done;
}
if (rc == NGX_DECLINED) {
break;
}
/* rc == NGX_OK */
if (ctx->status != V_OCSP_CERTSTATUS_GOOD) {
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp cached status \"%s\"",
OCSP_cert_status_str(ctx->status));
ocsp->cert_status = ctx->status;
goto done;
}
ocsp->ctx = NULL;
ngx_ssl_ocsp_done(ctx);
}
ngx_ssl_ocsp_request(ctx);
return;
done:
ocsp->status = rc;
if (c->ssl->in_ocsp) {
c->ssl->handshaked = 1;
c->ssl->handler(c);
}
}
static void
ngx_ssl_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
{
ngx_int_t rc;
ngx_ssl_ocsp_t *ocsp;
ngx_connection_t *c;
c = ctx->data;
ocsp = c->ssl->ocsp;
ocsp->ctx = NULL;
rc = ngx_ssl_ocsp_verify(ctx);
if (rc != NGX_OK) {
goto done;
}
rc = ngx_ssl_ocsp_cache_store(ctx);
if (rc != NGX_OK) {
goto done;
}
if (ctx->status != V_OCSP_CERTSTATUS_GOOD) {
ocsp->cert_status = ctx->status;
goto done;
}
ngx_ssl_ocsp_done(ctx);
ngx_ssl_ocsp_validate_next(c);
return;
done:
ocsp->status = rc;
ngx_ssl_ocsp_done(ctx);
if (c->ssl->in_ocsp) {
c->ssl->handshaked = 1;
c->ssl->handler(c);
}
}
static ngx_int_t
ngx_ssl_ocsp_responder(ngx_connection_t *c, ngx_ssl_ocsp_ctx_t *ctx)
{
char *s;
ngx_str_t responder;
ngx_url_t u;
STACK_OF(OPENSSL_STRING) *aia;
if (ctx->host.len) {
return NGX_OK;
}
/* extract OCSP responder URL from certificate */
aia = X509_get1_ocsp(ctx->cert);
if (aia == NULL) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"no OCSP responder URL in certificate");
return NGX_ERROR;
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
s = sk_OPENSSL_STRING_value(aia, 0);
#else
s = sk_value(aia, 0);
#endif
if (s == NULL) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"no OCSP responder URL in certificate");
X509_email_free(aia);
return NGX_ERROR;
}
responder.len = ngx_strlen(s);
responder.data = ngx_palloc(ctx->pool, responder.len);
if (responder.data == NULL) {
X509_email_free(aia);
return NGX_ERROR;
}
ngx_memcpy(responder.data, s, responder.len);
X509_email_free(aia);
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = responder;
u.default_port = 80;
u.uri_part = 1;
u.no_resolve = 1;
if (u.url.len > 7
&& ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0)
{
u.url.len -= 7;
u.url.data += 7;
} else {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"invalid URL prefix in OCSP responder \"%V\" "
"in certificate", &u.url);
return NGX_ERROR;
}
if (ngx_parse_url(ctx->pool, &u) != NGX_OK) {
if (u.err) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"%s in OCSP responder \"%V\" in certificate",
u.err, &u.url);
}
return NGX_ERROR;
}
if (u.host.len == 0) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"empty host in OCSP responder in certificate");
return NGX_ERROR;
}
ctx->addrs = u.addrs;
ctx->naddrs = u.naddrs;
ctx->host = u.host;
ctx->uri = u.uri;
ctx->port = u.port;
return NGX_OK;
}
ngx_int_t
ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s)
{
ngx_ssl_ocsp_t *ocsp;
ocsp = c->ssl->ocsp;
if (ocsp == NULL) {
return NGX_OK;
}
if (ocsp->status == NGX_ERROR) {
*s = "certificate status request failed";
return NGX_DECLINED;
}
switch (ocsp->cert_status) {
case V_OCSP_CERTSTATUS_GOOD:
return NGX_OK;
case V_OCSP_CERTSTATUS_REVOKED:
*s = "certificate revoked";
break;
default: /* V_OCSP_CERTSTATUS_UNKNOWN */
*s = "certificate status unknown";
}
return NGX_DECLINED;
}
void
ngx_ssl_ocsp_cleanup(ngx_connection_t *c)
{
ngx_ssl_ocsp_t *ocsp;
ocsp = c->ssl->ocsp;
if (ocsp == NULL) {
return;
}
if (ocsp->ctx) {
ngx_ssl_ocsp_done(ocsp->ctx);
ocsp->ctx = NULL;
}
if (ocsp->certs) {
sk_X509_pop_free(ocsp->certs, X509_free);
ocsp->certs = NULL;
}
}
static ngx_ssl_ocsp_ctx_t *
ngx_ssl_ocsp_start(ngx_log_t *log)
{ {
ngx_log_t *log;
ngx_pool_t *pool; ngx_pool_t *pool;
ngx_ssl_ocsp_ctx_t *ctx; ngx_ssl_ocsp_ctx_t *ctx;
pool = ngx_create_pool(2048, ngx_cycle->log); pool = ngx_create_pool(2048, log);
if (pool == NULL) { if (pool == NULL) {
return NULL; return NULL;
} }
@@ -884,6 +1322,36 @@ ngx_ssl_ocsp_error(ngx_ssl_ocsp_ctx_t *ctx)
} }
static void
ngx_ssl_ocsp_next(ngx_ssl_ocsp_ctx_t *ctx)
{
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp next");
if (++ctx->naddr >= ctx->naddrs) {
ngx_ssl_ocsp_error(ctx);
return;
}
ctx->request->pos = ctx->request->start;
if (ctx->response) {
ctx->response->last = ctx->response->pos;
}
if (ctx->peer.connection) {
ngx_close_connection(ctx->peer.connection);
ctx->peer.connection = NULL;
}
ctx->state = 0;
ctx->count = 0;
ctx->done = 0;
ngx_ssl_ocsp_connect(ctx);
}
static void static void
ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx) ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx)
{ {
@@ -909,6 +1377,14 @@ ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx)
} }
if (resolve == NGX_NO_RESOLVER) { if (resolve == NGX_NO_RESOLVER) {
if (ctx->naddrs == 0) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"no resolver defined to resolve %V", &ctx->host);
ngx_ssl_ocsp_error(ctx);
return;
}
ngx_log_error(NGX_LOG_WARN, ctx->log, 0, ngx_log_error(NGX_LOG_WARN, ctx->log, 0,
"no resolver defined to resolve %V", &ctx->host); "no resolver defined to resolve %V", &ctx->host);
goto connect; goto connect;
@@ -1022,16 +1498,17 @@ failed:
static void static void
ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx) ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
{ {
ngx_int_t rc; ngx_int_t rc;
ngx_addr_t *addr;
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp connect"); "ssl ocsp connect %ui/%ui", ctx->naddr, ctx->naddrs);
/* TODO: use all ip addresses */ addr = &ctx->addrs[ctx->naddr];
ctx->peer.sockaddr = ctx->addrs[0].sockaddr; ctx->peer.sockaddr = addr->sockaddr;
ctx->peer.socklen = ctx->addrs[0].socklen; ctx->peer.socklen = addr->socklen;
ctx->peer.name = &ctx->addrs[0].name; ctx->peer.name = &addr->name;
ctx->peer.get = ngx_event_get_peer; ctx->peer.get = ngx_event_get_peer;
ctx->peer.log = ctx->log; ctx->peer.log = ctx->log;
ctx->peer.log_error = NGX_ERROR_ERR; ctx->peer.log_error = NGX_ERROR_ERR;
@@ -1041,11 +1518,16 @@ ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp connect peer done"); "ssl ocsp connect peer done");
if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) { if (rc == NGX_ERROR) {
ngx_ssl_ocsp_error(ctx); ngx_ssl_ocsp_error(ctx);
return; return;
} }
if (rc == NGX_BUSY || rc == NGX_DECLINED) {
ngx_ssl_ocsp_next(ctx);
return;
}
ctx->peer.connection->data = ctx; ctx->peer.connection->data = ctx;
ctx->peer.connection->pool = ctx->pool; ctx->peer.connection->pool = ctx->pool;
@@ -1054,8 +1536,10 @@ ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
ctx->process = ngx_ssl_ocsp_process_status_line; ctx->process = ngx_ssl_ocsp_process_status_line;
ngx_add_timer(ctx->peer.connection->read, ctx->timeout); if (ctx->timeout) {
ngx_add_timer(ctx->peer.connection->write, ctx->timeout); ngx_add_timer(ctx->peer.connection->read, ctx->timeout);
ngx_add_timer(ctx->peer.connection->write, ctx->timeout);
}
if (rc == NGX_OK) { if (rc == NGX_OK) {
ngx_ssl_ocsp_write_handler(ctx->peer.connection->write); ngx_ssl_ocsp_write_handler(ctx->peer.connection->write);
@@ -1080,7 +1564,7 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
if (wev->timedout) { if (wev->timedout) {
ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
"OCSP responder timed out"); "OCSP responder timed out");
ngx_ssl_ocsp_error(ctx); ngx_ssl_ocsp_next(ctx);
return; return;
} }
@@ -1089,7 +1573,7 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
n = ngx_send(c, ctx->request->pos, size); n = ngx_send(c, ctx->request->pos, size);
if (n == NGX_ERROR) { if (n == NGX_ERROR) {
ngx_ssl_ocsp_error(ctx); ngx_ssl_ocsp_next(ctx);
return; return;
} }
@@ -1111,7 +1595,7 @@ ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
} }
} }
if (!wev->timer_set) { if (!wev->timer_set && ctx->timeout) {
ngx_add_timer(wev, ctx->timeout); ngx_add_timer(wev, ctx->timeout);
} }
} }
@@ -1134,7 +1618,7 @@ ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
if (rev->timedout) { if (rev->timedout) {
ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
"OCSP responder timed out"); "OCSP responder timed out");
ngx_ssl_ocsp_error(ctx); ngx_ssl_ocsp_next(ctx);
return; return;
} }
@@ -1158,7 +1642,7 @@ ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
rc = ctx->process(ctx); rc = ctx->process(ctx);
if (rc == NGX_ERROR) { if (rc == NGX_ERROR) {
ngx_ssl_ocsp_error(ctx); ngx_ssl_ocsp_next(ctx);
return; return;
} }
@@ -1189,7 +1673,7 @@ ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
ngx_log_error(NGX_LOG_ERR, ctx->log, 0, ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP responder prematurely closed connection"); "OCSP responder prematurely closed connection");
ngx_ssl_ocsp_error(ctx); ngx_ssl_ocsp_next(ctx);
} }
@@ -1831,6 +2315,368 @@ ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx)
} }
static ngx_int_t
ngx_ssl_ocsp_verify(ngx_ssl_ocsp_ctx_t *ctx)
{
int n;
size_t len;
X509_STORE *store;
const u_char *p;
OCSP_CERTID *id;
OCSP_RESPONSE *ocsp;
OCSP_BASICRESP *basic;
ASN1_GENERALIZEDTIME *thisupdate, *nextupdate;
ocsp = NULL;
basic = NULL;
id = NULL;
if (ctx->code != 200) {
goto error;
}
/* check the response */
len = ctx->response->last - ctx->response->pos;
p = ctx->response->pos;
ocsp = d2i_OCSP_RESPONSE(NULL, &p, len);
if (ocsp == NULL) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"d2i_OCSP_RESPONSE() failed");
goto error;
}
n = OCSP_response_status(ocsp);
if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP response not successful (%d: %s)",
n, OCSP_response_status_str(n));
goto error;
}
basic = OCSP_response_get1_basic(ocsp);
if (basic == NULL) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_response_get1_basic() failed");
goto error;
}
store = SSL_CTX_get_cert_store(ctx->ssl_ctx);
if (store == NULL) {
ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
"SSL_CTX_get_cert_store() failed");
goto error;
}
if (OCSP_basic_verify(basic, ctx->chain, store, ctx->flags) != 1) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_basic_verify() failed");
goto error;
}
id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
if (id == NULL) {
ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
"OCSP_cert_to_id() failed");
goto error;
}
if (OCSP_resp_find_status(basic, id, &ctx->status, NULL, NULL,
&thisupdate, &nextupdate)
!= 1)
{
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"certificate status not found in the OCSP response");
goto error;
}
if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) {
ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
"OCSP_check_validity() failed");
goto error;
}
if (nextupdate) {
ctx->valid = ngx_ssl_stapling_time(nextupdate);
if (ctx->valid == (time_t) NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
"invalid nextUpdate time in certificate status");
goto error;
}
} else {
ctx->valid = NGX_MAX_TIME_T_VALUE;
}
OCSP_CERTID_free(id);
OCSP_BASICRESP_free(basic);
OCSP_RESPONSE_free(ocsp);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp response, %s, %uz",
OCSP_cert_status_str(ctx->status), len);
return NGX_OK;
error:
if (id) {
OCSP_CERTID_free(id);
}
if (basic) {
OCSP_BASICRESP_free(basic);
}
if (ocsp) {
OCSP_RESPONSE_free(ocsp);
}
return NGX_ERROR;
}
ngx_int_t
ngx_ssl_ocsp_cache_init(ngx_shm_zone_t *shm_zone, void *data)
{
size_t len;
ngx_slab_pool_t *shpool;
ngx_ssl_ocsp_cache_t *cache;
if (data) {
shm_zone->data = data;
return NGX_OK;
}
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) {
shm_zone->data = shpool->data;
return NGX_OK;
}
cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_ocsp_cache_t));
if (cache == NULL) {
return NGX_ERROR;
}
shpool->data = cache;
shm_zone->data = cache;
ngx_rbtree_init(&cache->rbtree, &cache->sentinel,
ngx_str_rbtree_insert_value);
ngx_queue_init(&cache->expire_queue);
len = sizeof(" in OCSP cache \"\"") + shm_zone->shm.name.len;
shpool->log_ctx = ngx_slab_alloc(shpool, len);
if (shpool->log_ctx == NULL) {
return NGX_ERROR;
}
ngx_sprintf(shpool->log_ctx, " in OCSP cache \"%V\"%Z",
&shm_zone->shm.name);
shpool->log_nomem = 0;
return NGX_OK;
}
static ngx_int_t
ngx_ssl_ocsp_cache_lookup(ngx_ssl_ocsp_ctx_t *ctx)
{
uint32_t hash;
ngx_shm_zone_t *shm_zone;
ngx_slab_pool_t *shpool;
ngx_ssl_ocsp_cache_t *cache;
ngx_ssl_ocsp_cache_node_t *node;
shm_zone = ctx->shm_zone;
if (shm_zone == NULL) {
return NGX_DECLINED;
}
if (ngx_ssl_ocsp_create_key(ctx) != NGX_OK) {
return NGX_ERROR;
}
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp cache lookup");
cache = shm_zone->data;
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
hash = ngx_hash_key(ctx->key.data, ctx->key.len);
ngx_shmtx_lock(&shpool->mutex);
node = (ngx_ssl_ocsp_cache_node_t *)
ngx_str_rbtree_lookup(&cache->rbtree, &ctx->key, hash);
if (node) {
if (node->valid > ngx_time()) {
ctx->status = node->status;
ngx_shmtx_unlock(&shpool->mutex);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp cache hit, %s",
OCSP_cert_status_str(ctx->status));
return NGX_OK;
}
ngx_queue_remove(&node->queue);
ngx_rbtree_delete(&cache->rbtree, &node->node.node);
ngx_slab_free_locked(shpool, node);
ngx_shmtx_unlock(&shpool->mutex);
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp cache expired");
return NGX_DECLINED;
}
ngx_shmtx_unlock(&shpool->mutex);
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp cache miss");
return NGX_DECLINED;
}
static ngx_int_t
ngx_ssl_ocsp_cache_store(ngx_ssl_ocsp_ctx_t *ctx)
{
time_t now, valid;
uint32_t hash;
ngx_queue_t *q;
ngx_shm_zone_t *shm_zone;
ngx_slab_pool_t *shpool;
ngx_ssl_ocsp_cache_t *cache;
ngx_ssl_ocsp_cache_node_t *node;
shm_zone = ctx->shm_zone;
if (shm_zone == NULL) {
return NGX_OK;
}
valid = ctx->valid;
now = ngx_time();
if (valid < now) {
return NGX_OK;
}
if (valid == NGX_MAX_TIME_T_VALUE) {
valid = now + 3600;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp cache store, valid:%T", valid - now);
cache = shm_zone->data;
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
hash = ngx_hash_key(ctx->key.data, ctx->key.len);
ngx_shmtx_lock(&shpool->mutex);
node = ngx_slab_calloc_locked(shpool,
sizeof(ngx_ssl_ocsp_cache_node_t) + ctx->key.len);
if (node == NULL) {
if (!ngx_queue_empty(&cache->expire_queue)) {
q = ngx_queue_last(&cache->expire_queue);
node = ngx_queue_data(q, ngx_ssl_ocsp_cache_node_t, queue);
ngx_rbtree_delete(&cache->rbtree, &node->node.node);
ngx_queue_remove(q);
ngx_slab_free_locked(shpool, node);
node = ngx_slab_alloc_locked(shpool,
sizeof(ngx_ssl_ocsp_cache_node_t) + ctx->key.len);
}
if (node == NULL) {
ngx_shmtx_unlock(&shpool->mutex);
ngx_log_error(NGX_LOG_ALERT, ctx->log, 0,
"could not allocate new entry%s", shpool->log_ctx);
return NGX_ERROR;
}
}
node->node.str.len = ctx->key.len;
node->node.str.data = (u_char *) node + sizeof(ngx_ssl_ocsp_cache_node_t);
ngx_memcpy(node->node.str.data, ctx->key.data, ctx->key.len);
node->node.node.key = hash;
node->status = ctx->status;
node->valid = valid;
ngx_rbtree_insert(&cache->rbtree, &node->node.node);
ngx_queue_insert_head(&cache->expire_queue, &node->queue);
ngx_shmtx_unlock(&shpool->mutex);
return NGX_OK;
}
static ngx_int_t
ngx_ssl_ocsp_create_key(ngx_ssl_ocsp_ctx_t *ctx)
{
u_char *p;
X509_NAME *name;
ASN1_INTEGER *serial;
p = ngx_pnalloc(ctx->pool, 60);
if (p == NULL) {
return NGX_ERROR;
}
ctx->key.data = p;
ctx->key.len = 60;
name = X509_get_subject_name(ctx->issuer);
if (X509_NAME_digest(name, EVP_sha1(), p, NULL) == 0) {
return NGX_ERROR;
}
p += 20;
if (X509_pubkey_digest(ctx->issuer, EVP_sha1(), p, NULL) == 0) {
return NGX_ERROR;
}
p += 20;
serial = X509_get_serialNumber(ctx->cert);
if (serial->length > 20) {
return NGX_ERROR;
}
p = ngx_cpymem(p, serial->data, serial->length);
ngx_memzero(p, 20 - serial->length);
#if (NGX_DEBUG)
{
u_char buf[120];
ngx_hex_dump(buf, ctx->key.data, ctx->key.len);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp key %*s", sizeof(buf), buf);
}
#endif
return NGX_OK;
}
static u_char * static u_char *
ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len) ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len)
{ {
@@ -1891,4 +2737,50 @@ ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
} }
ngx_int_t
ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder,
ngx_uint_t depth, ngx_shm_zone_t *shm_zone)
{
ngx_log_error(NGX_LOG_EMERG, ssl->log, 0,
"\"ssl_ocsp\" is not supported on this platform");
return NGX_ERROR;
}
ngx_int_t
ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
{
return NGX_OK;
}
ngx_int_t
ngx_ssl_ocsp_validate(ngx_connection_t *c)
{
return NGX_OK;
}
ngx_int_t
ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s)
{
return NGX_OK;
}
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)
{
return NGX_OK;
}
#endif #endif
+28
View File
@@ -960,6 +960,22 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK; return NGX_OK;
} }
if (p->upstream_done) {
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
"input data after close");
return NGX_OK;
}
if (p->length == 0) {
p->upstream_done = 1;
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
return NGX_OK;
}
cl = ngx_chain_get_free_buf(p->pool, &p->free); cl = ngx_chain_get_free_buf(p->pool, &p->free);
if (cl == NULL) { if (cl == NULL) {
return NGX_ERROR; return NGX_ERROR;
@@ -987,6 +1003,18 @@ ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK; return NGX_OK;
} }
if (b->last - b->pos > p->length) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
b->last = b->pos + p->length;
p->upstream_done = 1;
return NGX_OK;
}
p->length -= b->last - b->pos; p->length -= b->last - b->pos;
return NGX_OK; return NGX_OK;
+24
View File
@@ -34,3 +34,27 @@ ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted)
ev->handler(ev); ev->handler(ev);
} }
} }
void
ngx_event_move_posted_next(ngx_cycle_t *cycle)
{
ngx_queue_t *q;
ngx_event_t *ev;
for (q = ngx_queue_head(&ngx_posted_next_events);
q != ngx_queue_sentinel(&ngx_posted_next_events);
q = ngx_queue_next(q))
{
ev = ngx_queue_data(q, ngx_event_t, queue);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"posted next event %p", ev);
ev->ready = 1;
ev->available = -1;
}
ngx_queue_add(&ngx_posted_events, &ngx_posted_next_events);
ngx_queue_init(&ngx_posted_next_events);
}
+1
View File
@@ -39,6 +39,7 @@
void ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted); void ngx_event_process_posted(ngx_cycle_t *cycle, ngx_queue_t *posted);
void ngx_event_move_posted_next(ngx_cycle_t *cycle);
extern ngx_queue_t ngx_posted_accept_events; extern ngx_queue_t ngx_posted_accept_events;
+18 -19
View File
@@ -25,7 +25,6 @@ static ngx_int_t ngx_http_auth_basic_crypt_handler(ngx_http_request_t *r,
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, static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r,
ngx_str_t *realm); ngx_str_t *realm);
static void ngx_http_auth_basic_close(ngx_file_t *file);
static void *ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf); static void *ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child); void *parent, void *child);
@@ -177,8 +176,8 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
offset); offset);
if (n == NGX_ERROR) { if (n == NGX_ERROR) {
ngx_http_auth_basic_close(&file); rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
return NGX_HTTP_INTERNAL_SERVER_ERROR; goto cleanup;
} }
if (n == 0) { if (n == 0) {
@@ -219,12 +218,11 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
if (buf[i] == LF || buf[i] == CR || buf[i] == ':') { if (buf[i] == LF || buf[i] == CR || buf[i] == ':') {
buf[i] = '\0'; buf[i] = '\0';
ngx_http_auth_basic_close(&file);
pwd.len = i - passwd; pwd.len = i - passwd;
pwd.data = &buf[passwd]; pwd.data = &buf[passwd];
return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm); rc = ngx_http_auth_basic_crypt_handler(r, &pwd, &realm);
goto cleanup;
} }
break; break;
@@ -251,8 +249,6 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
offset += n; offset += n;
} }
ngx_http_auth_basic_close(&file);
if (state == sw_passwd) { if (state == sw_passwd) {
pwd.len = i - passwd; pwd.len = i - passwd;
pwd.data = ngx_pnalloc(r->pool, pwd.len + 1); pwd.data = ngx_pnalloc(r->pool, pwd.len + 1);
@@ -262,14 +258,26 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1); ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);
return ngx_http_auth_basic_crypt_handler(r, &pwd, &realm); rc = ngx_http_auth_basic_crypt_handler(r, &pwd, &realm);
goto cleanup;
} }
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"user \"%V\" was not found in \"%s\"", "user \"%V\" was not found in \"%s\"",
&r->headers_in.user, user_file.data); &r->headers_in.user, user_file.data);
return ngx_http_auth_basic_set_realm(r, &realm); rc = ngx_http_auth_basic_set_realm(r, &realm);
cleanup:
if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
ngx_close_file_n " \"%s\" failed", user_file.data);
}
ngx_explicit_memzero(buf, NGX_HTTP_AUTH_BUF_SIZE);
return rc;
} }
@@ -338,15 +346,6 @@ ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm)
return NGX_HTTP_UNAUTHORIZED; return NGX_HTTP_UNAUTHORIZED;
} }
static void
ngx_http_auth_basic_close(ngx_file_t *file)
{
if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, file->log, ngx_errno,
ngx_close_file_n " \"%s\" failed", file->name.data);
}
}
static void * static void *
ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf) ngx_http_auth_basic_create_loc_conf(ngx_conf_t *cf)
+10 -28
View File
@@ -56,7 +56,7 @@ static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx,
static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt); static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt);
static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err,
ngx_int_t not_found, char *failed, u_char *path); ngx_int_t not_found, char *failed, u_char *path);
static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path); static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r);
static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child); void *parent, void *child);
@@ -285,7 +285,7 @@ ngx_http_dav_put_handler(ngx_http_request_t *r)
} }
if (status == NGX_HTTP_CREATED) { if (status == NGX_HTTP_CREATED) {
if (ngx_http_dav_location(r, path.data) != NGX_OK) { if (ngx_http_dav_location(r) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return; return;
} }
@@ -312,7 +312,7 @@ ngx_http_dav_delete_handler(ngx_http_request_t *r)
ngx_file_info_t fi; ngx_file_info_t fi;
ngx_http_dav_loc_conf_t *dlcf; ngx_http_dav_loc_conf_t *dlcf;
if (r->headers_in.content_length_n > 0) { if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"DELETE with body is unsupported"); "DELETE with body is unsupported");
return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
@@ -495,7 +495,7 @@ ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
size_t root; size_t root;
ngx_str_t path; ngx_str_t path;
if (r->headers_in.content_length_n > 0) { if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"MKCOL with body is unsupported"); "MKCOL with body is unsupported");
return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
@@ -513,7 +513,6 @@ ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
} }
*(p - 1) = '\0'; *(p - 1) = '\0';
r->uri.len--;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http mkcol path: \"%s\"", path.data); "http mkcol path: \"%s\"", path.data);
@@ -521,7 +520,7 @@ ngx_http_dav_mkcol_handler(ngx_http_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access)) if (ngx_create_dir(path.data, ngx_dir_access(dlcf->access))
!= NGX_FILE_ERROR) != NGX_FILE_ERROR)
{ {
if (ngx_http_dav_location(r, path.data) != NGX_OK) { if (ngx_http_dav_location(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
} }
@@ -550,7 +549,9 @@ ngx_http_dav_copy_move_handler(ngx_http_request_t *r)
ngx_http_dav_copy_ctx_t copy; ngx_http_dav_copy_ctx_t copy;
ngx_http_dav_loc_conf_t *dlcf; ngx_http_dav_loc_conf_t *dlcf;
if (r->headers_in.content_length_n > 0) { if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"COPY and MOVE with body are unsupported");
return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
} }
@@ -1069,35 +1070,16 @@ ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found,
static ngx_int_t static ngx_int_t
ngx_http_dav_location(ngx_http_request_t *r, u_char *path) ngx_http_dav_location(ngx_http_request_t *r)
{ {
u_char *location;
ngx_http_core_loc_conf_t *clcf;
r->headers_out.location = ngx_list_push(&r->headers_out.headers); r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) { if (r->headers_out.location == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!clcf->alias && clcf->root_lengths == NULL) {
location = path + clcf->root.len;
} else {
location = ngx_pnalloc(r->pool, r->uri.len);
if (location == NULL) {
ngx_http_clear_location(r);
return NGX_ERROR;
}
ngx_memcpy(location, r->uri.data, r->uri.len);
}
r->headers_out.location->hash = 1; r->headers_out.location->hash = 1;
ngx_str_set(&r->headers_out.location->key, "Location"); ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value.len = r->uri.len; r->headers_out.location->value = r->uri;
r->headers_out.location->value.data = location;
return NGX_OK; return NGX_OK;
} }
+122 -14
View File
@@ -81,12 +81,15 @@ typedef struct {
size_t length; size_t length;
size_t padding; size_t padding;
off_t rest;
ngx_chain_t *free; ngx_chain_t *free;
ngx_chain_t *busy; ngx_chain_t *busy;
unsigned fastcgi_stdout:1; unsigned fastcgi_stdout:1;
unsigned large_stderr:1; unsigned large_stderr:1;
unsigned header_sent:1; unsigned header_sent:1;
unsigned closed:1;
ngx_array_t *split_parts; ngx_array_t *split_parts;
@@ -2075,13 +2078,31 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
static ngx_int_t static ngx_int_t
ngx_http_fastcgi_input_filter_init(void *data) ngx_http_fastcgi_input_filter_init(void *data)
{ {
ngx_http_request_t *r = data; ngx_http_request_t *r = data;
ngx_http_upstream_t *u;
ngx_http_fastcgi_ctx_t *f;
ngx_http_fastcgi_loc_conf_t *flcf; ngx_http_fastcgi_loc_conf_t *flcf;
u = r->upstream;
f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
r->upstream->pipe->length = flcf->keep_conn ? u->pipe->length = flcf->keep_conn ?
(off_t) sizeof(ngx_http_fastcgi_header_t) : -1; (off_t) sizeof(ngx_http_fastcgi_header_t) : -1;
if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
|| u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
{
f->rest = 0;
} else if (r->method == NGX_HTTP_HEAD) {
f->rest = -2;
} else {
f->rest = u->headers_in.content_length_n;
}
return NGX_OK; return NGX_OK;
} }
@@ -2106,6 +2127,15 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
if (p->upstream_done || f->closed) {
r->upstream->keepalive = 0;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi data after close");
return NGX_OK;
}
b = NULL; b = NULL;
prev = &buf->shadow; prev = &buf->shadow;
@@ -2128,13 +2158,25 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) {
f->state = ngx_http_fastcgi_st_padding; f->state = ngx_http_fastcgi_st_padding;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi closed stdout");
if (f->rest > 0) {
ngx_log_error(NGX_LOG_ERR, p->log, 0,
"upstream prematurely closed "
"FastCGI stdout");
p->upstream_error = 1;
p->upstream_eof = 0;
f->closed = 1;
break;
}
if (!flcf->keep_conn) { if (!flcf->keep_conn) {
p->upstream_done = 1; p->upstream_done = 1;
} }
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi closed stdout");
continue; continue;
} }
@@ -2143,6 +2185,18 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http fastcgi sent end request"); "http fastcgi sent end request");
if (f->rest > 0) {
ngx_log_error(NGX_LOG_ERR, p->log, 0,
"upstream prematurely closed "
"FastCGI request");
p->upstream_error = 1;
p->upstream_eof = 0;
f->closed = 1;
break;
}
if (!flcf->keep_conn) { if (!flcf->keep_conn) {
p->upstream_done = 1; p->upstream_done = 1;
break; break;
@@ -2252,6 +2306,18 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
break; break;
} }
if (f->rest == -2) {
f->rest = r->upstream->headers_in.content_length_n;
}
if (f->rest == 0) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
p->upstream_done = 1;
break;
}
cl = ngx_chain_get_free_buf(p->pool, &p->free); cl = ngx_chain_get_free_buf(p->pool, &p->free);
if (cl == NULL) { if (cl == NULL) {
return NGX_ERROR; return NGX_ERROR;
@@ -2289,15 +2355,27 @@ ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
f->pos += f->length; f->pos += f->length;
b->last = f->pos; b->last = f->pos;
continue; } else {
f->length -= f->last - f->pos;
f->pos = f->last;
b->last = f->last;
} }
f->length -= f->last - f->pos; if (f->rest > 0) {
b->last = f->last; if (b->last - b->pos > f->rest) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
break; b->last = b->pos + f->rest;
p->upstream_done = 1;
break;
}
f->rest -= b->last - b->pos;
}
} }
if (flcf->keep_conn) { if (flcf->keep_conn) {
@@ -2391,6 +2469,14 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) {
if (f->rest > 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream prematurely closed "
"FastCGI request");
u->error = 1;
break;
}
if (f->pos + f->padding < f->last) { if (f->pos + f->padding < f->last) {
u->length = 0; u->length = 0;
break; break;
@@ -2486,6 +2572,14 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
break; break;
} }
if (f->rest == 0) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
u->length = 0;
break;
}
cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs); cl = ngx_chain_get_free_buf(r->pool, &u->free_bufs);
if (cl == NULL) { if (cl == NULL) {
return NGX_ERROR; return NGX_ERROR;
@@ -2510,13 +2604,27 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
f->pos += f->length; f->pos += f->length;
b->last = f->pos; b->last = f->pos;
continue; } else {
f->length -= f->last - f->pos;
f->pos = f->last;
b->last = f->last;
} }
f->length -= f->last - f->pos; if (f->rest > 0) {
b->last = f->last;
break; if (b->last - b->pos > f->rest) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
b->last = b->pos + f->rest;
u->length = 0;
break;
}
f->rest -= b->last - b->pos;
}
} }
return NGX_OK; return NGX_OK;
+249 -45
View File
@@ -27,6 +27,9 @@ typedef struct {
ngx_str_t host; ngx_str_t host;
ngx_uint_t host_set; ngx_uint_t host_set;
ngx_array_t *grpc_lengths;
ngx_array_t *grpc_values;
#if (NGX_HTTP_SSL) #if (NGX_HTTP_SSL)
ngx_uint_t ssl; ngx_uint_t ssl;
ngx_uint_t ssl_protocols; ngx_uint_t ssl_protocols;
@@ -81,6 +84,8 @@ typedef struct {
ngx_uint_t pings; ngx_uint_t pings;
ngx_uint_t settings; ngx_uint_t settings;
off_t length;
ssize_t send_window; ssize_t send_window;
size_t recv_window; size_t recv_window;
@@ -117,8 +122,11 @@ typedef struct {
unsigned end_stream:1; unsigned end_stream:1;
unsigned done:1; unsigned done:1;
unsigned status:1; unsigned status:1;
unsigned rst:1;
ngx_http_request_t *request; ngx_http_request_t *request;
ngx_str_t host;
} ngx_http_grpc_ctx_t; } ngx_http_grpc_ctx_t;
@@ -135,6 +143,8 @@ typedef struct {
} ngx_http_grpc_frame_t; } ngx_http_grpc_frame_t;
static ngx_int_t ngx_http_grpc_eval(ngx_http_request_t *r,
ngx_http_grpc_ctx_t *ctx, ngx_http_grpc_loc_conf_t *glcf);
static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_grpc_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_grpc_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in); static ngx_int_t ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in);
@@ -524,22 +534,40 @@ ngx_http_grpc_handler(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
} }
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t));
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ctx->request = r;
ngx_http_set_ctx(r, ctx, ngx_http_grpc_module);
glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
u = r->upstream; u = r->upstream;
#if (NGX_HTTP_SSL) if (glcf->grpc_lengths == NULL) {
u->ssl = (glcf->upstream.ssl != NULL); ctx->host = glcf->host;
if (u->ssl) { #if (NGX_HTTP_SSL)
ngx_str_set(&u->schema, "grpcs://"); u->ssl = (glcf->upstream.ssl != NULL);
if (u->ssl) {
ngx_str_set(&u->schema, "grpcs://");
} else {
ngx_str_set(&u->schema, "grpc://");
}
#else
ngx_str_set(&u->schema, "grpc://");
#endif
} else { } else {
ngx_str_set(&u->schema, "grpc://"); if (ngx_http_grpc_eval(r, ctx, glcf) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
} }
#else
ngx_str_set(&u->schema, "grpc://");
#endif
u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module; u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module;
@@ -551,15 +579,6 @@ ngx_http_grpc_handler(ngx_http_request_t *r)
u->abort_request = ngx_http_grpc_abort_request; u->abort_request = ngx_http_grpc_abort_request;
u->finalize_request = ngx_http_grpc_finalize_request; u->finalize_request = ngx_http_grpc_finalize_request;
ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_grpc_ctx_t));
if (ctx == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
ctx->request = r;
ngx_http_set_ctx(r, ctx, ngx_http_grpc_module);
u->input_filter_init = ngx_http_grpc_filter_init; u->input_filter_init = ngx_http_grpc_filter_init;
u->input_filter = ngx_http_grpc_filter; u->input_filter = ngx_http_grpc_filter;
u->input_filter_ctx = ctx; u->input_filter_ctx = ctx;
@@ -576,6 +595,103 @@ ngx_http_grpc_handler(ngx_http_request_t *r)
} }
static ngx_int_t
ngx_http_grpc_eval(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx,
ngx_http_grpc_loc_conf_t *glcf)
{
size_t add;
ngx_url_t url;
ngx_http_upstream_t *u;
ngx_memzero(&url, sizeof(ngx_url_t));
if (ngx_http_script_run(r, &url.url, glcf->grpc_lengths->elts, 0,
glcf->grpc_values->elts)
== NULL)
{
return NGX_ERROR;
}
if (url.url.len > 7
&& ngx_strncasecmp(url.url.data, (u_char *) "grpc://", 7) == 0)
{
add = 7;
} else if (url.url.len > 8
&& ngx_strncasecmp(url.url.data, (u_char *) "grpcs://", 8) == 0)
{
#if (NGX_HTTP_SSL)
add = 8;
r->upstream->ssl = 1;
#else
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"grpcs protocol requires SSL support");
return NGX_ERROR;
#endif
} else {
add = 0;
}
u = r->upstream;
if (add) {
u->schema.len = add;
u->schema.data = url.url.data;
url.url.data += add;
url.url.len -= add;
} else {
ngx_str_set(&u->schema, "grpc://");
}
url.no_resolve = 1;
if (ngx_parse_url(r->pool, &url) != NGX_OK) {
if (url.err) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"%s in upstream \"%V\"", url.err, &url.url);
}
return NGX_ERROR;
}
u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
if (u->resolved == NULL) {
return NGX_ERROR;
}
if (url.addrs) {
u->resolved->sockaddr = url.addrs[0].sockaddr;
u->resolved->socklen = url.addrs[0].socklen;
u->resolved->name = url.addrs[0].name;
u->resolved->naddrs = 1;
}
u->resolved->host = url.host;
u->resolved->port = url.port;
u->resolved->no_port = url.no_port;
if (url.family != AF_UNIX) {
if (url.no_port) {
ctx->host = url.host;
} else {
ctx->host.len = url.host.len + 1 + url.port_text.len;
ctx->host.data = url.host.data;
}
} else {
ngx_str_set(&ctx->host, "localhost");
}
return NGX_OK;
}
static ngx_int_t static ngx_int_t
ngx_http_grpc_create_request(ngx_http_request_t *r) ngx_http_grpc_create_request(ngx_http_request_t *r)
{ {
@@ -587,6 +703,7 @@ ngx_http_grpc_create_request(ngx_http_request_t *r)
ngx_chain_t *cl, *body; ngx_chain_t *cl, *body;
ngx_list_part_t *part; ngx_list_part_t *part;
ngx_table_elt_t *header; ngx_table_elt_t *header;
ngx_http_grpc_ctx_t *ctx;
ngx_http_upstream_t *u; ngx_http_upstream_t *u;
ngx_http_grpc_frame_t *f; ngx_http_grpc_frame_t *f;
ngx_http_script_code_pt code; ngx_http_script_code_pt code;
@@ -598,6 +715,8 @@ ngx_http_grpc_create_request(ngx_http_request_t *r)
glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module); glcf = ngx_http_get_module_loc_conf(r, ngx_http_grpc_module);
ctx = ngx_http_get_module_ctx(r, ngx_http_grpc_module);
len = sizeof(ngx_http_grpc_connection_start) - 1 len = sizeof(ngx_http_grpc_connection_start) - 1
+ sizeof(ngx_http_grpc_frame_t); /* headers frame */ + sizeof(ngx_http_grpc_frame_t); /* headers frame */
@@ -637,10 +756,10 @@ ngx_http_grpc_create_request(ngx_http_request_t *r)
/* :authority header */ /* :authority header */
if (!glcf->host_set) { if (!glcf->host_set) {
len += 1 + NGX_HTTP_V2_INT_OCTETS + glcf->host.len; len += 1 + NGX_HTTP_V2_INT_OCTETS + ctx->host.len;
if (tmp_len < glcf->host.len) { if (tmp_len < ctx->host.len) {
tmp_len = glcf->host.len; tmp_len = ctx->host.len;
} }
} }
@@ -785,7 +904,7 @@ ngx_http_grpc_create_request(ngx_http_request_t *r)
} }
#if (NGX_HTTP_SSL) #if (NGX_HTTP_SSL)
if (glcf->ssl) { if (u->ssl) {
*b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); *b->last++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -846,11 +965,11 @@ ngx_http_grpc_create_request(ngx_http_request_t *r)
if (!glcf->host_set) { if (!glcf->host_set) {
*b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX); *b->last++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX);
b->last = ngx_http_v2_write_value(b->last, glcf->host.data, b->last = ngx_http_v2_write_value(b->last, ctx->host.data,
glcf->host.len, tmp); ctx->host.len, tmp);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"grpc header: \":authority: %V\"", &glcf->host); "grpc header: \":authority: %V\"", &ctx->host);
} }
ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
@@ -1089,6 +1208,7 @@ ngx_http_grpc_reinit_request(ngx_http_request_t *r)
ctx->end_stream = 0; ctx->end_stream = 0;
ctx->done = 0; ctx->done = 0;
ctx->status = 0; ctx->status = 0;
ctx->rst = 0;
ctx->connection = NULL; ctx->connection = NULL;
return NGX_OK; return NGX_OK;
@@ -1835,10 +1955,28 @@ ngx_http_grpc_filter_init(void *data)
r = ctx->request; r = ctx->request;
u = r->upstream; u = r->upstream;
u->length = 1; if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
|| u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
|| r->method == NGX_HTTP_HEAD)
{
ctx->length = 0;
} else {
ctx->length = u->headers_in.content_length_n;
}
if (ctx->end_stream) { if (ctx->end_stream) {
if (ctx->length > 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream prematurely closed stream");
return NGX_ERROR;
}
u->length = 0; u->length = 0;
} else {
u->length = 1;
} }
return NGX_OK; return NGX_OK;
@@ -1881,6 +2019,12 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
if (ctx->done) { if (ctx->done) {
if (ctx->length > 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream prematurely closed stream");
return NGX_ERROR;
}
/* /*
* We have finished parsing the response and the * We have finished parsing the response and the
* remaining control frames. If there are unsent * remaining control frames. If there are unsent
@@ -1934,6 +2078,17 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR; return NGX_ERROR;
} }
if (ctx->length != -1) {
if ((off_t) ctx->rest > ctx->length) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent response body larger "
"than indicated content length");
return NGX_ERROR;
}
ctx->length -= ctx->rest;
}
if (ctx->rest > ctx->recv_window) { if (ctx->rest > ctx->recv_window) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream violated stream flow control, " "upstream violated stream flow control, "
@@ -1972,7 +2127,10 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR; return NGX_ERROR;
} }
if (ctx->stream_id && ctx->done) { if (ctx->stream_id && ctx->done
&& ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME
&& ctx->type != NGX_HTTP_V2_WINDOW_UPDATE_FRAME)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent frame for closed stream %ui", "upstream sent frame for closed stream %ui",
ctx->stream_id); ctx->stream_id);
@@ -2015,11 +2173,21 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR; return NGX_ERROR;
} }
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, if (ctx->error || !ctx->done) {
"upstream rejected request with error %ui", ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
ctx->error); "upstream rejected request with error %ui",
ctx->error);
return NGX_ERROR;
}
return NGX_ERROR; if (ctx->rst) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent frame for closed stream %ui",
ctx->stream_id);
return NGX_ERROR;
}
ctx->rst = 1;
} }
if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
@@ -4319,15 +4487,23 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
if (clcf->noname && conf->upstream.upstream == NULL) { if (clcf->noname
&& conf->upstream.upstream == NULL && conf->grpc_lengths == NULL)
{
conf->upstream.upstream = prev->upstream.upstream; conf->upstream.upstream = prev->upstream.upstream;
conf->host = prev->host; conf->host = prev->host;
conf->grpc_lengths = prev->grpc_lengths;
conf->grpc_values = prev->grpc_values;
#if (NGX_HTTP_SSL) #if (NGX_HTTP_SSL)
conf->upstream.ssl = prev->upstream.ssl; conf->upstream.ssl = prev->upstream.ssl;
#endif #endif
} }
if (clcf->lmt_excpt && clcf->handler == NULL && conf->upstream.upstream) { if (clcf->lmt_excpt && clcf->handler == NULL
&& (conf->upstream.upstream || conf->grpc_lengths))
{
clcf->handler = ngx_http_grpc_handler; clcf->handler = ngx_http_grpc_handler;
} }
@@ -4537,18 +4713,54 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ {
ngx_http_grpc_loc_conf_t *glcf = conf; ngx_http_grpc_loc_conf_t *glcf = conf;
size_t add; size_t add;
ngx_str_t *value, *url; ngx_str_t *value, *url;
ngx_url_t u; ngx_url_t u;
ngx_http_core_loc_conf_t *clcf; ngx_uint_t n;
ngx_http_core_loc_conf_t *clcf;
ngx_http_script_compile_t sc;
if (glcf->upstream.upstream) { if (glcf->upstream.upstream || glcf->grpc_lengths) {
return "is duplicate"; return "is duplicate";
} }
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_grpc_handler;
if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
clcf->auto_redirect = 1;
}
value = cf->args->elts; value = cf->args->elts;
url = &value[1]; url = &value[1];
n = ngx_http_script_variables_count(url);
if (n) {
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = url;
sc.lengths = &glcf->grpc_lengths;
sc.values = &glcf->grpc_values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
#if (NGX_HTTP_SSL)
glcf->ssl = 1;
#endif
return NGX_CONF_OK;
}
if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) { if (ngx_strncasecmp(url->data, (u_char *) "grpc://", 7) == 0) {
add = 7; add = 7;
@@ -4593,14 +4805,6 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_set(&glcf->host, "localhost"); ngx_str_set(&glcf->host, "localhost");
} }
clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
clcf->handler = ngx_http_grpc_handler;
if (clcf->name.len && clcf->name.data[clcf->name.len - 1] == '/') {
clcf->auto_redirect = 1;
}
return NGX_CONF_OK; return NGX_CONF_OK;
} }
+1 -1
View File
@@ -163,7 +163,7 @@ ngx_http_index_handler(ngx_http_request_t *r)
name = ngx_http_map_uri_to_path(r, &path, &root, reserve); name = ngx_http_map_uri_to_path(r, &path, &root, reserve);
if (name == NULL) { if (name == NULL) {
return NGX_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
} }
allocated = path.data + path.len - name; allocated = path.data + path.len - name;
+138 -50
View File
@@ -10,36 +10,49 @@
#include <ngx_http.h> #include <ngx_http.h>
#define NGX_HTTP_LIMIT_CONN_PASSED 1
#define NGX_HTTP_LIMIT_CONN_REJECTED 2
#define NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN 3
typedef struct { typedef struct {
u_char color; u_char color;
u_char len; u_char len;
u_short conn; u_short conn;
u_char data[1]; u_char data[1];
} ngx_http_limit_conn_node_t; } ngx_http_limit_conn_node_t;
typedef struct { typedef struct {
ngx_shm_zone_t *shm_zone; ngx_shm_zone_t *shm_zone;
ngx_rbtree_node_t *node; ngx_rbtree_node_t *node;
} ngx_http_limit_conn_cleanup_t; } ngx_http_limit_conn_cleanup_t;
typedef struct { typedef struct {
ngx_rbtree_t *rbtree; ngx_rbtree_t rbtree;
ngx_http_complex_value_t key; ngx_rbtree_node_t sentinel;
} ngx_http_limit_conn_shctx_t;
typedef struct {
ngx_http_limit_conn_shctx_t *sh;
ngx_slab_pool_t *shpool;
ngx_http_complex_value_t key;
} ngx_http_limit_conn_ctx_t; } ngx_http_limit_conn_ctx_t;
typedef struct { typedef struct {
ngx_shm_zone_t *shm_zone; ngx_shm_zone_t *shm_zone;
ngx_uint_t conn; ngx_uint_t conn;
} ngx_http_limit_conn_limit_t; } ngx_http_limit_conn_limit_t;
typedef struct { typedef struct {
ngx_array_t limits; ngx_array_t limits;
ngx_uint_t log_level; ngx_uint_t log_level;
ngx_uint_t status_code; ngx_uint_t status_code;
ngx_flag_t dry_run;
} ngx_http_limit_conn_conf_t; } ngx_http_limit_conn_conf_t;
@@ -48,6 +61,8 @@ static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree,
static void ngx_http_limit_conn_cleanup(void *data); static void ngx_http_limit_conn_cleanup(void *data);
static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool);
static ngx_int_t ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf); static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf);
static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
void *child); void *child);
@@ -55,6 +70,7 @@ static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static ngx_int_t ngx_http_limit_conn_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf); static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf);
@@ -102,12 +118,19 @@ static ngx_command_t ngx_http_limit_conn_commands[] = {
offsetof(ngx_http_limit_conn_conf_t, status_code), offsetof(ngx_http_limit_conn_conf_t, status_code),
&ngx_http_limit_conn_status_bounds }, &ngx_http_limit_conn_status_bounds },
{ ngx_string("limit_conn_dry_run"),
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_limit_conn_conf_t, dry_run),
NULL },
ngx_null_command ngx_null_command
}; };
static ngx_http_module_t ngx_http_limit_conn_module_ctx = { static ngx_http_module_t ngx_http_limit_conn_module_ctx = {
NULL, /* preconfiguration */ ngx_http_limit_conn_add_variables, /* preconfiguration */
ngx_http_limit_conn_init, /* postconfiguration */ ngx_http_limit_conn_init, /* postconfiguration */
NULL, /* create main configuration */ NULL, /* create main configuration */
@@ -137,6 +160,22 @@ ngx_module_t ngx_http_limit_conn_module = {
}; };
static ngx_http_variable_t ngx_http_limit_conn_vars[] = {
{ ngx_string("limit_conn_status"), NULL,
ngx_http_limit_conn_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
ngx_http_null_variable
};
static ngx_str_t ngx_http_limit_conn_status[] = {
ngx_string("PASSED"),
ngx_string("REJECTED"),
ngx_string("REJECTED_DRY_RUN")
};
static ngx_int_t static ngx_int_t
ngx_http_limit_conn_handler(ngx_http_request_t *r) ngx_http_limit_conn_handler(ngx_http_request_t *r)
{ {
@@ -144,7 +183,6 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
uint32_t hash; uint32_t hash;
ngx_str_t key; ngx_str_t key;
ngx_uint_t i; ngx_uint_t i;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node; ngx_rbtree_node_t *node;
ngx_pool_cleanup_t *cln; ngx_pool_cleanup_t *cln;
ngx_http_limit_conn_ctx_t *ctx; ngx_http_limit_conn_ctx_t *ctx;
@@ -153,7 +191,7 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
ngx_http_limit_conn_limit_t *limits; ngx_http_limit_conn_limit_t *limits;
ngx_http_limit_conn_cleanup_t *lccln; ngx_http_limit_conn_cleanup_t *lccln;
if (r->main->limit_conn_set) { if (r->main->limit_conn_status) {
return NGX_DECLINED; return NGX_DECLINED;
} }
@@ -179,15 +217,13 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
continue; continue;
} }
r->main->limit_conn_set = 1; r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_PASSED;
hash = ngx_crc32_short(key.data, key.len); hash = ngx_crc32_short(key.data, key.len);
shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; ngx_shmtx_lock(&ctx->shpool->mutex);
ngx_shmtx_lock(&shpool->mutex); node = ngx_http_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
node = ngx_http_limit_conn_lookup(ctx->rbtree, &key, hash);
if (node == NULL) { if (node == NULL) {
@@ -195,11 +231,20 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
+ offsetof(ngx_http_limit_conn_node_t, data) + offsetof(ngx_http_limit_conn_node_t, data)
+ key.len; + key.len;
node = ngx_slab_alloc_locked(shpool, n); node = ngx_slab_alloc_locked(ctx->shpool, n);
if (node == NULL) { if (node == NULL) {
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_http_limit_conn_cleanup_all(r->pool); ngx_http_limit_conn_cleanup_all(r->pool);
if (lccf->dry_run) {
r->main->limit_conn_status =
NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN;
return NGX_DECLINED;
}
r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED;
return lccf->status_code; return lccf->status_code;
} }
@@ -210,7 +255,7 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
lc->conn = 1; lc->conn = 1;
ngx_memcpy(lc->data, key.data, key.len); ngx_memcpy(lc->data, key.data, key.len);
ngx_rbtree_insert(ctx->rbtree, node); ngx_rbtree_insert(&ctx->sh->rbtree, node);
} else { } else {
@@ -218,13 +263,23 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
if ((ngx_uint_t) lc->conn >= limits[i].conn) { if ((ngx_uint_t) lc->conn >= limits[i].conn) {
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_log_error(lccf->log_level, r->connection->log, 0, ngx_log_error(lccf->log_level, r->connection->log, 0,
"limiting connections by zone \"%V\"", "limiting connections%s by zone \"%V\"",
lccf->dry_run ? ", dry run," : "",
&limits[i].shm_zone->shm.name); &limits[i].shm_zone->shm.name);
ngx_http_limit_conn_cleanup_all(r->pool); ngx_http_limit_conn_cleanup_all(r->pool);
if (lccf->dry_run) {
r->main->limit_conn_status =
NGX_HTTP_LIMIT_CONN_REJECTED_DRY_RUN;
return NGX_DECLINED;
}
r->main->limit_conn_status = NGX_HTTP_LIMIT_CONN_REJECTED;
return lccf->status_code; return lccf->status_code;
} }
@@ -234,7 +289,7 @@ ngx_http_limit_conn_handler(ngx_http_request_t *r)
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"limit conn: %08Xi %d", node->key, lc->conn); "limit conn: %08Xi %d", node->key, lc->conn);
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
cln = ngx_pool_cleanup_add(r->pool, cln = ngx_pool_cleanup_add(r->pool,
sizeof(ngx_http_limit_conn_cleanup_t)); sizeof(ngx_http_limit_conn_cleanup_t));
@@ -338,17 +393,15 @@ ngx_http_limit_conn_cleanup(void *data)
{ {
ngx_http_limit_conn_cleanup_t *lccln = data; ngx_http_limit_conn_cleanup_t *lccln = data;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node; ngx_rbtree_node_t *node;
ngx_http_limit_conn_ctx_t *ctx; ngx_http_limit_conn_ctx_t *ctx;
ngx_http_limit_conn_node_t *lc; ngx_http_limit_conn_node_t *lc;
ctx = lccln->shm_zone->data; ctx = lccln->shm_zone->data;
shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
node = lccln->node; node = lccln->node;
lc = (ngx_http_limit_conn_node_t *) &node->color; lc = (ngx_http_limit_conn_node_t *) &node->color;
ngx_shmtx_lock(&shpool->mutex); ngx_shmtx_lock(&ctx->shpool->mutex);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0,
"limit conn cleanup: %08Xi %d", node->key, lc->conn); "limit conn cleanup: %08Xi %d", node->key, lc->conn);
@@ -356,11 +409,11 @@ ngx_http_limit_conn_cleanup(void *data)
lc->conn--; lc->conn--;
if (lc->conn == 0) { if (lc->conn == 0) {
ngx_rbtree_delete(ctx->rbtree, node); ngx_rbtree_delete(&ctx->sh->rbtree, node);
ngx_slab_free_locked(shpool, node); ngx_slab_free_locked(ctx->shpool, node);
} }
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
} }
@@ -386,8 +439,6 @@ ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
ngx_http_limit_conn_ctx_t *octx = data; ngx_http_limit_conn_ctx_t *octx = data;
size_t len; size_t len;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *sentinel;
ngx_http_limit_conn_ctx_t *ctx; ngx_http_limit_conn_ctx_t *ctx;
ctx = shm_zone->data; ctx = shm_zone->data;
@@ -406,48 +457,63 @@ ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
return NGX_ERROR; return NGX_ERROR;
} }
ctx->rbtree = octx->rbtree; ctx->sh = octx->sh;
ctx->shpool = octx->shpool;
return NGX_OK; return NGX_OK;
} }
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) { if (shm_zone->shm.exists) {
ctx->rbtree = shpool->data; ctx->sh = ctx->shpool->data;
return NGX_OK; return NGX_OK;
} }
ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_conn_shctx_t));
if (ctx->rbtree == NULL) { if (ctx->sh == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
shpool->data = ctx->rbtree; ctx->shpool->data = ctx->sh;
sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
if (sentinel == NULL) {
return NGX_ERROR;
}
ngx_rbtree_init(ctx->rbtree, sentinel,
ngx_http_limit_conn_rbtree_insert_value); ngx_http_limit_conn_rbtree_insert_value);
len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len; len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
shpool->log_ctx = ngx_slab_alloc(shpool, len); ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
if (shpool->log_ctx == NULL) { if (ctx->shpool->log_ctx == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z", ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
&shm_zone->shm.name); &shm_zone->shm.name);
return NGX_OK; return NGX_OK;
} }
static ngx_int_t
ngx_http_limit_conn_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->main->limit_conn_status == 0) {
v->not_found = 1;
return NGX_OK;
}
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->len = ngx_http_limit_conn_status[r->main->limit_conn_status - 1].len;
v->data = ngx_http_limit_conn_status[r->main->limit_conn_status - 1].data;
return NGX_OK;
}
static void * static void *
ngx_http_limit_conn_create_conf(ngx_conf_t *cf) ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
{ {
@@ -466,6 +532,7 @@ ngx_http_limit_conn_create_conf(ngx_conf_t *cf)
conf->log_level = NGX_CONF_UNSET_UINT; conf->log_level = NGX_CONF_UNSET_UINT;
conf->status_code = NGX_CONF_UNSET_UINT; conf->status_code = NGX_CONF_UNSET_UINT;
conf->dry_run = NGX_CONF_UNSET;
return conf; return conf;
} }
@@ -485,6 +552,8 @@ ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->status_code, prev->status_code, ngx_conf_merge_uint_value(conf->status_code, prev->status_code,
NGX_HTTP_SERVICE_UNAVAILABLE); NGX_HTTP_SERVICE_UNAVAILABLE);
ngx_conf_merge_value(conf->dry_run, prev->dry_run, 0);
return NGX_CONF_OK; return NGX_CONF_OK;
} }
@@ -651,6 +720,25 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
} }
static ngx_int_t
ngx_http_limit_conn_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_limit_conn_vars; v->name.len; v++) {
var = ngx_http_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static ngx_int_t static ngx_int_t
ngx_http_limit_conn_init(ngx_conf_t *cf) ngx_http_limit_conn_init(ngx_conf_t *cf)
{ {
+6 -3
View File
@@ -485,10 +485,11 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
if (u->length == (ssize_t) ctx->rest) { if (u->length == (ssize_t) ctx->rest) {
if (ngx_strncmp(b->last, if (bytes > u->length
|| ngx_strncmp(b->last,
ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest, ngx_http_memcached_end + NGX_HTTP_MEMCACHED_END - ctx->rest,
bytes) bytes)
!= 0) != 0)
{ {
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
"memcached sent invalid trailer"); "memcached sent invalid trailer");
@@ -540,7 +541,9 @@ ngx_http_memcached_filter(void *data, ssize_t bytes)
last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END); last += (size_t) (u->length - NGX_HTTP_MEMCACHED_END);
if (ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0) { if (bytes > u->length
|| ngx_strncmp(last, ngx_http_memcached_end, b->last - last) != 0)
{
ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0, ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
"memcached sent invalid trailer"); "memcached sent invalid trailer");
+64 -11
View File
@@ -3116,6 +3116,13 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
"chunk samples sizes:%uL", "chunk samples sizes:%uL",
trak->start_chunk_samples_size); trak->start_chunk_samples_size);
if (trak->start_chunk_samples_size > (uint64_t) mp4->end) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"too large mp4 start samples size in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
if (mp4->length) { if (mp4->length) {
if (trak->end_sample - trak->start_sample > entries) { if (trak->end_sample - trak->start_sample > entries) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
@@ -3135,6 +3142,13 @@ ngx_http_mp4_update_stsz_atom(ngx_http_mp4_file_t *mp4,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"mp4 stsz end_chunk_samples_size:%uL", "mp4 stsz end_chunk_samples_size:%uL",
trak->end_chunk_samples_size); trak->end_chunk_samples_size);
if (trak->end_chunk_samples_size > (uint64_t) mp4->end) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"too large mp4 end samples size in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
} }
atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos); atom_size = sizeof(ngx_mp4_stsz_atom_t) + (data->last - data->pos);
@@ -3226,6 +3240,7 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
{ {
size_t atom_size; size_t atom_size;
uint32_t entries; uint32_t entries;
uint64_t chunk_offset, samples_size;
ngx_buf_t *atom, *data; ngx_buf_t *atom, *data;
ngx_mp4_stco_atom_t *stco_atom; ngx_mp4_stco_atom_t *stco_atom;
@@ -3256,8 +3271,19 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
data->pos += trak->start_chunk * sizeof(uint32_t); data->pos += trak->start_chunk * sizeof(uint32_t);
trak->start_offset = ngx_mp4_get_32value(data->pos); chunk_offset = ngx_mp4_get_32value(data->pos);
trak->start_offset += trak->start_chunk_samples_size; samples_size = trak->start_chunk_samples_size;
if (chunk_offset > (uint64_t) mp4->end - samples_size
|| chunk_offset + samples_size > NGX_MAX_UINT32_VALUE)
{
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"too large chunk offset in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
trak->start_offset = chunk_offset + samples_size;
ngx_mp4_set_32value(data->pos, trak->start_offset); ngx_mp4_set_32value(data->pos, trak->start_offset);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -3276,9 +3302,19 @@ ngx_http_mp4_update_stco_atom(ngx_http_mp4_file_t *mp4,
data->last = data->pos + entries * sizeof(uint32_t); data->last = data->pos + entries * sizeof(uint32_t);
if (entries) { if (entries) {
trak->end_offset = chunk_offset = ngx_mp4_get_32value(data->last - sizeof(uint32_t));
ngx_mp4_get_32value(data->last - sizeof(uint32_t)); samples_size = trak->end_chunk_samples_size;
trak->end_offset += trak->end_chunk_samples_size;
if (chunk_offset > (uint64_t) mp4->end - samples_size
|| chunk_offset + samples_size > NGX_MAX_UINT32_VALUE)
{
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"too large chunk offset in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
trak->end_offset = chunk_offset + samples_size;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"end chunk offset:%O", trak->end_offset); "end chunk offset:%O", trak->end_offset);
@@ -3409,7 +3445,7 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
ngx_http_mp4_trak_t *trak) ngx_http_mp4_trak_t *trak)
{ {
size_t atom_size; size_t atom_size;
uint64_t entries; uint64_t entries, chunk_offset, samples_size;
ngx_buf_t *atom, *data; ngx_buf_t *atom, *data;
ngx_mp4_co64_atom_t *co64_atom; ngx_mp4_co64_atom_t *co64_atom;
@@ -3440,8 +3476,17 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
data->pos += trak->start_chunk * sizeof(uint64_t); data->pos += trak->start_chunk * sizeof(uint64_t);
trak->start_offset = ngx_mp4_get_64value(data->pos); chunk_offset = ngx_mp4_get_64value(data->pos);
trak->start_offset += trak->start_chunk_samples_size; samples_size = trak->start_chunk_samples_size;
if (chunk_offset > (uint64_t) mp4->end - samples_size) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"too large chunk offset in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
trak->start_offset = chunk_offset + samples_size;
ngx_mp4_set_64value(data->pos, trak->start_offset); ngx_mp4_set_64value(data->pos, trak->start_offset);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
@@ -3460,9 +3505,17 @@ ngx_http_mp4_update_co64_atom(ngx_http_mp4_file_t *mp4,
data->last = data->pos + entries * sizeof(uint64_t); data->last = data->pos + entries * sizeof(uint64_t);
if (entries) { if (entries) {
trak->end_offset = chunk_offset = ngx_mp4_get_64value(data->last - sizeof(uint64_t));
ngx_mp4_get_64value(data->last - sizeof(uint64_t)); samples_size = trak->end_chunk_samples_size;
trak->end_offset += trak->end_chunk_samples_size;
if (chunk_offset > (uint64_t) mp4->end - samples_size) {
ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0,
"too large chunk offset in \"%s\"",
mp4->file.name.data);
return NGX_ERROR;
}
trak->end_offset = chunk_offset + samples_size;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
"end chunk offset:%O", trak->end_offset); "end chunk offset:%O", trak->end_offset);
+75 -12
View File
@@ -2015,6 +2015,25 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK; return NGX_OK;
} }
if (p->upstream_done) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http proxy data after close");
return NGX_OK;
}
if (p->length == 0) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
r = p->input_ctx;
r->upstream->keepalive = 0;
p->upstream_done = 1;
return NGX_OK;
}
cl = ngx_chain_get_free_buf(p->pool, &p->free); cl = ngx_chain_get_free_buf(p->pool, &p->free);
if (cl == NULL) { if (cl == NULL) {
return NGX_ERROR; return NGX_ERROR;
@@ -2042,20 +2061,23 @@ ngx_http_proxy_copy_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_OK; return NGX_OK;
} }
if (b->last - b->pos > p->length) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
b->last = b->pos + p->length;
p->upstream_done = 1;
return NGX_OK;
}
p->length -= b->last - b->pos; p->length -= b->last - b->pos;
if (p->length == 0) { if (p->length == 0) {
r = p->input_ctx; r = p->input_ctx;
p->upstream_done = 1;
r->upstream->keepalive = !r->upstream->headers_in.connection_close; r->upstream->keepalive = !r->upstream->headers_in.connection_close;
} else if (p->length < 0) {
r = p->input_ctx;
p->upstream_done = 1;
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
} }
return NGX_OK; return NGX_OK;
@@ -2082,6 +2104,23 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
return NGX_ERROR; return NGX_ERROR;
} }
if (p->upstream_done) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http proxy data after close");
return NGX_OK;
}
if (p->length == 0) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent data after final chunk");
r->upstream->keepalive = 0;
p->upstream_done = 1;
return NGX_OK;
}
b = NULL; b = NULL;
prev = &buf->shadow; prev = &buf->shadow;
@@ -2144,9 +2183,15 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
/* a whole response has been parsed successfully */ /* a whole response has been parsed successfully */
p->upstream_done = 1; p->length = 0;
r->upstream->keepalive = !r->upstream->headers_in.connection_close; r->upstream->keepalive = !r->upstream->headers_in.connection_close;
if (buf->pos != buf->last) {
ngx_log_error(NGX_LOG_WARN, p->log, 0,
"upstream sent data after final chunk");
r->upstream->keepalive = 0;
}
break; break;
} }
@@ -2161,13 +2206,13 @@ ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
/* invalid response */ /* invalid response */
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, p->log, 0,
"upstream sent invalid chunked response"); "upstream sent invalid chunked response");
return NGX_ERROR; return NGX_ERROR;
} }
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_HTTP, p->log, 0,
"http proxy chunked state %ui, length %O", "http proxy chunked state %ui, length %O",
ctx->chunked.state, p->length); ctx->chunked.state, p->length);
@@ -2227,6 +2272,18 @@ ngx_http_proxy_non_buffered_copy_filter(void *data, ssize_t bytes)
return NGX_OK; return NGX_OK;
} }
if (bytes > u->length) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
cl->buf->last = cl->buf->pos + u->length;
u->length = 0;
return NGX_OK;
}
u->length -= bytes; u->length -= bytes;
if (u->length == 0) { if (u->length == 0) {
@@ -2313,6 +2370,12 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
u->keepalive = !u->headers_in.connection_close; u->keepalive = !u->headers_in.connection_close;
u->length = 0; u->length = 0;
if (buf->pos != buf->last) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent data after final chunk");
u->keepalive = 0;
}
break; break;
} }
@@ -318,6 +318,11 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts; value = cf->args->elts;
if (value[2].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty replacement");
return NGX_CONF_ERROR;
}
ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
rc.pattern = value[1]; rc.pattern = value[1];
+36
View File
@@ -49,6 +49,7 @@ static ngx_int_t ngx_http_scgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r); static ngx_int_t ngx_http_scgi_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_scgi_input_filter_init(void *data);
static void ngx_http_scgi_abort_request(ngx_http_request_t *r); static void ngx_http_scgi_abort_request(ngx_http_request_t *r);
static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc); static void ngx_http_scgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
@@ -534,6 +535,10 @@ ngx_http_scgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->pipe->input_ctx = r; u->pipe->input_ctx = r;
u->input_filter_init = ngx_http_scgi_input_filter_init;
u->input_filter = ngx_http_upstream_non_buffered_filter;
u->input_filter_ctx = r;
if (!scf->upstream.request_buffering if (!scf->upstream.request_buffering
&& scf->upstream.pass_request_body && scf->upstream.pass_request_body
&& !r->headers_in.chunked) && !r->headers_in.chunked)
@@ -1145,6 +1150,37 @@ ngx_http_scgi_process_header(ngx_http_request_t *r)
} }
static ngx_int_t
ngx_http_scgi_input_filter_init(void *data)
{
ngx_http_request_t *r = data;
ngx_http_upstream_t *u;
u = r->upstream;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http scgi filter init s:%ui l:%O",
u->headers_in.status_n, u->headers_in.content_length_n);
if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
|| u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
{
u->pipe->length = 0;
u->length = 0;
} else if (r->method == NGX_HTTP_HEAD) {
u->pipe->length = -1;
u->length = -1;
} else {
u->pipe->length = u->headers_in.content_length_n;
u->length = u->headers_in.content_length_n;
}
return NGX_OK;
}
static void static void
ngx_http_scgi_abort_request(ngx_http_request_t *r) ngx_http_scgi_abort_request(ngx_http_request_t *r)
{ {
@@ -180,6 +180,11 @@ ngx_http_slice_header_filter(ngx_http_request_t *r)
r->headers_out.content_range->hash = 0; r->headers_out.content_range->hash = 0;
r->headers_out.content_range = NULL; r->headers_out.content_range = NULL;
if (r->headers_out.accept_ranges) {
r->headers_out.accept_ranges->hash = 0;
r->headers_out.accept_ranges = NULL;
}
r->allow_ranges = 1; r->allow_ranges = 1;
r->subrequest_ranges = 1; r->subrequest_ranges = 1;
r->single_range = 1; r->single_range = 1;
+151 -5
View File
@@ -50,6 +50,8 @@ static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_ssl_ocsp_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf); static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf);
@@ -74,6 +76,14 @@ static ngx_conf_enum_t ngx_http_ssl_verify[] = {
}; };
static ngx_conf_enum_t ngx_http_ssl_ocsp[] = {
{ ngx_string("off"), 0 },
{ ngx_string("on"), 1 },
{ ngx_string("leaf"), 2 },
{ ngx_null_string, 0 }
};
static ngx_conf_deprecated_t ngx_http_ssl_deprecated = { static ngx_conf_deprecated_t ngx_http_ssl_deprecated = {
ngx_conf_deprecated, "ssl", "listen ... ssl" ngx_conf_deprecated, "ssl", "listen ... ssl"
}; };
@@ -221,6 +231,27 @@ static ngx_command_t ngx_http_ssl_commands[] = {
offsetof(ngx_http_ssl_srv_conf_t, crl), offsetof(ngx_http_ssl_srv_conf_t, crl),
NULL }, NULL },
{ ngx_string("ssl_ocsp"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_enum_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, ocsp),
&ngx_http_ssl_ocsp },
{ ngx_string("ssl_ocsp_responder"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_ssl_srv_conf_t, ocsp_responder),
NULL },
{ ngx_string("ssl_ocsp_cache"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_http_ssl_ocsp_cache,
NGX_HTTP_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("ssl_stapling"), { ngx_string("ssl_stapling"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot, ngx_conf_set_flag_slot,
@@ -603,6 +634,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
* sscf->crl = { 0, NULL }; * sscf->crl = { 0, NULL };
* sscf->ciphers = { 0, NULL }; * sscf->ciphers = { 0, NULL };
* sscf->shm_zone = NULL; * sscf->shm_zone = NULL;
* sscf->ocsp_responder = { 0, NULL };
* sscf->stapling_file = { 0, NULL }; * sscf->stapling_file = { 0, NULL };
* sscf->stapling_responder = { 0, NULL }; * sscf->stapling_responder = { 0, NULL };
*/ */
@@ -621,6 +653,8 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
sscf->session_timeout_tls13 = NGX_CONF_UNSET; sscf->session_timeout_tls13 = NGX_CONF_UNSET;
sscf->session_tickets = NGX_CONF_UNSET; sscf->session_tickets = NGX_CONF_UNSET;
sscf->session_ticket_keys = NGX_CONF_UNSET_PTR; sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
sscf->ocsp = NGX_CONF_UNSET_UINT;
sscf->ocsp_cache_zone = NGX_CONF_UNSET_PTR;
sscf->stapling = NGX_CONF_UNSET; sscf->stapling = NGX_CONF_UNSET;
sscf->stapling_verify = NGX_CONF_UNSET; sscf->stapling_verify = NGX_CONF_UNSET;
sscf->dyn_rec_enable = NGX_CONF_UNSET; sscf->dyn_rec_enable = NGX_CONF_UNSET;
@@ -691,6 +725,11 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS);
ngx_conf_merge_uint_value(conf->ocsp, prev->ocsp, 0);
ngx_conf_merge_str_value(conf->ocsp_responder, prev->ocsp_responder, "");
ngx_conf_merge_ptr_value(conf->ocsp_cache_zone,
prev->ocsp_cache_zone, NULL);
ngx_conf_merge_value(conf->stapling, prev->stapling, 0); ngx_conf_merge_value(conf->stapling, prev->stapling, 0);
ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0); ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0);
ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, ""); ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, "");
@@ -866,6 +905,23 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
if (conf->ocsp) {
if (conf->verify == 3) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"\"ssl_ocsp\" is incompatible with "
"\"ssl_verify_client optional_no_ca\"");
return NGX_CONF_ERROR;
}
if (ngx_ssl_ocsp(cf, &conf->ssl, &conf->ocsp_responder, conf->ocsp,
conf->ocsp_cache_zone)
!= NGX_OK)
{
return NGX_CONF_ERROR;
}
}
if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) { if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
@@ -1186,6 +1242,85 @@ invalid:
} }
static char *
ngx_http_ssl_ocsp_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_ssl_srv_conf_t *sscf = conf;
size_t len;
ngx_int_t n;
ngx_str_t *value, name, size;
ngx_uint_t j;
if (sscf->ocsp_cache_zone != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
if (ngx_strcmp(value[1].data, "off") == 0) {
sscf->ocsp_cache_zone = NULL;
return NGX_CONF_OK;
}
if (value[1].len <= sizeof("shared:") - 1
|| ngx_strncmp(value[1].data, "shared:", sizeof("shared:") - 1) != 0)
{
goto invalid;
}
len = 0;
for (j = sizeof("shared:") - 1; j < value[1].len; j++) {
if (value[1].data[j] == ':') {
break;
}
len++;
}
if (len == 0) {
goto invalid;
}
name.len = len;
name.data = value[1].data + sizeof("shared:") - 1;
size.len = value[1].len - j - 1;
size.data = name.data + len + 1;
n = ngx_parse_size(&size);
if (n == NGX_ERROR) {
goto invalid;
}
if (n < (ngx_int_t) (8 * ngx_pagesize)) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"OCSP cache \"%V\" is too small", &value[1]);
return NGX_CONF_ERROR;
}
sscf->ocsp_cache_zone = ngx_shared_memory_add(cf, &name, n,
&ngx_http_ssl_module_ctx);
if (sscf->ocsp_cache_zone == NULL) {
return NGX_CONF_ERROR;
}
sscf->ocsp_cache_zone->init = ngx_ssl_ocsp_cache_init;
return NGX_CONF_OK;
invalid:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid OCSP cache \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
static ngx_int_t static ngx_int_t
ngx_http_ssl_init(ngx_conf_t *cf) ngx_http_ssl_init(ngx_conf_t *cf)
{ {
@@ -1204,17 +1339,28 @@ ngx_http_ssl_init(ngx_conf_t *cf)
sscf = cscfp[s]->ctx->srv_conf[ngx_http_ssl_module.ctx_index]; sscf = cscfp[s]->ctx->srv_conf[ngx_http_ssl_module.ctx_index];
if (sscf->ssl.ctx == NULL || !sscf->stapling) { if (sscf->ssl.ctx == NULL) {
continue; continue;
} }
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index]; clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
if (ngx_ssl_stapling_resolver(cf, &sscf->ssl, clcf->resolver, if (sscf->stapling) {
if (ngx_ssl_stapling_resolver(cf, &sscf->ssl, clcf->resolver,
clcf->resolver_timeout)
!= NGX_OK)
{
return NGX_ERROR;
}
}
if (sscf->ocsp) {
if (ngx_ssl_ocsp_resolver(cf, &sscf->ssl, clcf->resolver,
clcf->resolver_timeout) clcf->resolver_timeout)
!= NGX_OK) != NGX_OK)
{ {
return NGX_ERROR; return NGX_ERROR;
}
} }
} }
+4
View File
@@ -55,6 +55,10 @@ typedef struct {
ngx_flag_t session_tickets; ngx_flag_t session_tickets;
ngx_array_t *session_ticket_keys; ngx_array_t *session_ticket_keys;
ngx_uint_t ocsp;
ngx_str_t ocsp_responder;
ngx_shm_zone_t *ocsp_cache_zone;
ngx_flag_t stapling; ngx_flag_t stapling;
ngx_flag_t stapling_verify; ngx_flag_t stapling_verify;
ngx_str_t stapling_file; ngx_str_t stapling_file;
+2 -2
View File
@@ -157,8 +157,8 @@ ngx_http_static_handler(ngx_http_request_t *r)
len = r->uri.len + 1; len = r->uri.len + 1;
if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { if (!clcf->alias && r->args.len == 0) {
location = path.data + clcf->root.len; location = path.data + root;
*last = '/'; *last = '/';
@@ -275,6 +275,7 @@ found:
c->idle = 0; c->idle = 0;
c->sent = 0; c->sent = 0;
c->data = NULL;
c->log = pc->log; c->log = pc->log;
c->read->log = pc->log; c->read->log = pc->log;
c->write->log = pc->log; c->write->log = pc->log;
+37
View File
@@ -67,6 +67,7 @@ static ngx_int_t ngx_http_uwsgi_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_uwsgi_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r); static ngx_int_t ngx_http_uwsgi_process_status_line(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r); static ngx_int_t ngx_http_uwsgi_process_header(ngx_http_request_t *r);
static ngx_int_t ngx_http_uwsgi_input_filter_init(void *data);
static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r); static void ngx_http_uwsgi_abort_request(ngx_http_request_t *r);
static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r, static void ngx_http_uwsgi_finalize_request(ngx_http_request_t *r,
ngx_int_t rc); ngx_int_t rc);
@@ -703,6 +704,10 @@ ngx_http_uwsgi_handler(ngx_http_request_t *r)
u->pipe->input_filter = ngx_event_pipe_copy_input_filter; u->pipe->input_filter = ngx_event_pipe_copy_input_filter;
u->pipe->input_ctx = r; u->pipe->input_ctx = r;
u->input_filter_init = ngx_http_uwsgi_input_filter_init;
u->input_filter = ngx_http_upstream_non_buffered_filter;
u->input_filter_ctx = r;
if (!uwcf->upstream.request_buffering if (!uwcf->upstream.request_buffering
&& uwcf->upstream.pass_request_body && uwcf->upstream.pass_request_body
&& !r->headers_in.chunked) && !r->headers_in.chunked)
@@ -1141,6 +1146,7 @@ ngx_http_uwsgi_create_request(ngx_http_request_t *r)
r->upstream->request_bufs = cl; r->upstream->request_bufs = cl;
} }
b->flush = 1;
cl->next = NULL; cl->next = NULL;
return NGX_OK; return NGX_OK;
@@ -1355,6 +1361,37 @@ ngx_http_uwsgi_process_header(ngx_http_request_t *r)
} }
static ngx_int_t
ngx_http_uwsgi_input_filter_init(void *data)
{
ngx_http_request_t *r = data;
ngx_http_upstream_t *u;
u = r->upstream;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http uwsgi filter init s:%ui l:%O",
u->headers_in.status_n, u->headers_in.content_length_n);
if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
|| u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED)
{
u->pipe->length = 0;
u->length = 0;
} else if (r->method == NGX_HTTP_HEAD) {
u->pipe->length = -1;
u->length = -1;
} else {
u->pipe->length = u->headers_in.content_length_n;
u->length = u->headers_in.content_length_n;
}
return NGX_OK;
}
static void static void
ngx_http_uwsgi_abort_request(ngx_http_request_t *r) ngx_http_uwsgi_abort_request(ngx_http_request_t *r)
{ {
@@ -233,6 +233,7 @@ ngx_http_xslt_header_filter(ngx_http_request_t *r)
ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module); ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module);
r->main_filter_need_in_memory = 1; r->main_filter_need_in_memory = 1;
r->allow_ranges = 0;
return NGX_OK; return NGX_OK;
} }
+2 -2
View File
@@ -1469,14 +1469,14 @@ ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
NGX_HASH_WILDCARD_KEY); NGX_HASH_WILDCARD_KEY);
if (rc == NGX_ERROR) { if (rc == NGX_ERROR) {
return NGX_ERROR; goto failed;
} }
if (rc == NGX_DECLINED) { if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0, ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"invalid server name or wildcard \"%V\" on %V", "invalid server name or wildcard \"%V\" on %V",
&name[n].name, &addr->opt.addr_text); &name[n].name, &addr->opt.addr_text);
return NGX_ERROR; goto failed;
} }
if (rc == NGX_BUSY) { if (rc == NGX_BUSY) {
+1
View File
@@ -160,6 +160,7 @@ struct ngx_http_file_cache_s {
ngx_path_t *path; ngx_path_t *path;
off_t min_free;
off_t max_size; off_t max_size;
size_t bsize; size_t bsize;
+113 -33
View File
@@ -21,6 +21,9 @@ typedef struct {
#define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2 #define NGX_HTTP_REQUEST_BODY_FILE_CLEAN 2
static ngx_int_t ngx_http_core_auth_delay(ngx_http_request_t *r);
static void ngx_http_core_auth_delay_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r); static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r);
static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r,
ngx_http_location_tree_node_t *node); ngx_http_location_tree_node_t *node);
@@ -534,6 +537,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, satisfy), offsetof(ngx_http_core_loc_conf_t, satisfy),
&ngx_http_core_satisfy }, &ngx_http_core_satisfy },
{ ngx_string("auth_delay"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_msec_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, auth_delay),
NULL },
{ ngx_string("internal"), { ngx_string("internal"),
NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS, NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
ngx_http_core_internal, ngx_http_core_internal,
@@ -1138,6 +1148,10 @@ ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
/* rc == NGX_ERROR || rc == NGX_HTTP_... */ /* rc == NGX_ERROR || rc == NGX_HTTP_... */
if (rc == NGX_HTTP_UNAUTHORIZED) {
return ngx_http_core_auth_delay(r);
}
ngx_http_finalize_request(r, rc); ngx_http_finalize_request(r, rc);
return NGX_OK; return NGX_OK;
} }
@@ -1155,12 +1169,17 @@ ngx_http_core_post_access_phase(ngx_http_request_t *r,
access_code = r->access_code; access_code = r->access_code;
if (access_code) { if (access_code) {
r->access_code = 0;
if (access_code == NGX_HTTP_FORBIDDEN) { if (access_code == NGX_HTTP_FORBIDDEN) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"access forbidden by rule"); "access forbidden by rule");
} }
r->access_code = 0; if (access_code == NGX_HTTP_UNAUTHORIZED) {
return ngx_http_core_auth_delay(r);
}
ngx_http_finalize_request(r, access_code); ngx_http_finalize_request(r, access_code);
return NGX_OK; return NGX_OK;
} }
@@ -1170,6 +1189,65 @@ ngx_http_core_post_access_phase(ngx_http_request_t *r,
} }
static ngx_int_t
ngx_http_core_auth_delay(ngx_http_request_t *r)
{
ngx_http_core_loc_conf_t *clcf;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->auth_delay == 0) {
ngx_http_finalize_request(r, NGX_HTTP_UNAUTHORIZED);
return NGX_OK;
}
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"delaying unauthorized request");
if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
r->read_event_handler = ngx_http_test_reading;
r->write_event_handler = ngx_http_core_auth_delay_handler;
r->connection->write->delayed = 1;
ngx_add_timer(r->connection->write, clcf->auth_delay);
/*
* trigger an additional event loop iteration
* to ensure constant-time processing
*/
ngx_post_event(r->connection->write, &ngx_posted_next_events);
return NGX_OK;
}
static void
ngx_http_core_auth_delay_handler(ngx_http_request_t *r)
{
ngx_event_t *wev;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"auth delay handler");
wev = r->connection->write;
if (wev->delayed) {
if (ngx_handle_write_event(wev, 0) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
}
return;
}
ngx_http_finalize_request(r, NGX_HTTP_UNAUTHORIZED);
}
ngx_int_t ngx_int_t
ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph) ngx_http_phase_handler_t *ph)
@@ -1857,7 +1935,8 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
} }
} }
last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1); last = ngx_copy(last, r->uri.data + alias, r->uri.len - alias);
*last = '\0';
return last; return last;
} }
@@ -2680,43 +2759,41 @@ ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr,
u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive) u_char *xff, size_t xfflen, ngx_array_t *proxies, int recursive)
{ {
u_char *p; u_char *p;
ngx_int_t rc;
ngx_addr_t paddr; ngx_addr_t paddr;
ngx_uint_t found;
if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) { found = 0;
return NGX_DECLINED;
}
for (p = xff + xfflen - 1; p > xff; p--, xfflen--) { do {
if (*p != ' ' && *p != ',') {
break;
}
}
for ( /* void */ ; p > xff; p--) { if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) {
if (*p == ' ' || *p == ',') { return found ? NGX_DONE : NGX_DECLINED;
p++;
break;
}
}
if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff)) != NGX_OK) {
return NGX_DECLINED;
}
*addr = paddr;
if (recursive && p > xff) {
rc = ngx_http_get_forwarded_addr_internal(r, addr, xff, p - 1 - xff,
proxies, 1);
if (rc == NGX_DECLINED) {
return NGX_DONE;
} }
/* rc == NGX_OK || rc == NGX_DONE */ for (p = xff + xfflen - 1; p > xff; p--, xfflen--) {
return rc; if (*p != ' ' && *p != ',') {
} break;
}
}
for ( /* void */ ; p > xff; p--) {
if (*p == ' ' || *p == ',') {
p++;
break;
}
}
if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff))
!= NGX_OK)
{
return found ? NGX_DONE : NGX_DECLINED;
}
*addr = paddr;
found = 1;
xfflen = p - 1 - xff;
} while (recursive && p > xff);
return NGX_OK; return NGX_OK;
} }
@@ -3409,6 +3486,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
clcf->client_body_timeout = NGX_CONF_UNSET_MSEC; clcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
clcf->satisfy = NGX_CONF_UNSET_UINT; clcf->satisfy = NGX_CONF_UNSET_UINT;
clcf->auth_delay = NGX_CONF_UNSET_MSEC;
clcf->if_modified_since = NGX_CONF_UNSET_UINT; clcf->if_modified_since = NGX_CONF_UNSET_UINT;
clcf->max_ranges = NGX_CONF_UNSET_UINT; clcf->max_ranges = NGX_CONF_UNSET_UINT;
clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT; clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
@@ -3626,6 +3704,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|NGX_HTTP_KEEPALIVE_DISABLE_MSIE6)); |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6));
ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy, ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
NGX_HTTP_SATISFY_ALL); NGX_HTTP_SATISFY_ALL);
ngx_conf_merge_msec_value(conf->auth_delay, prev->auth_delay, 0);
ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since, ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
NGX_HTTP_IMS_EXACT); NGX_HTTP_IMS_EXACT);
ngx_conf_merge_uint_value(conf->max_ranges, prev->max_ranges, ngx_conf_merge_uint_value(conf->max_ranges, prev->max_ranges,
@@ -4706,6 +4785,7 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
case NGX_HTTP_TO_HTTPS: case NGX_HTTP_TO_HTTPS:
case NGX_HTTPS_CERT_ERROR: case NGX_HTTPS_CERT_ERROR:
case NGX_HTTPS_NO_CERT: case NGX_HTTPS_NO_CERT:
case NGX_HTTP_REQUEST_HEADER_TOO_LARGE:
err->overwrite = NGX_HTTP_BAD_REQUEST; err->overwrite = NGX_HTTP_BAD_REQUEST;
} }
} }
+1
View File
@@ -363,6 +363,7 @@ struct ngx_http_core_loc_conf_s {
ngx_msec_t lingering_time; /* lingering_time */ ngx_msec_t lingering_time; /* lingering_time */
ngx_msec_t lingering_timeout; /* lingering_timeout */ ngx_msec_t lingering_timeout; /* lingering_timeout */
ngx_msec_t resolver_timeout; /* resolver_timeout */ ngx_msec_t resolver_timeout; /* resolver_timeout */
ngx_msec_t auth_delay; /* auth_delay */
ngx_resolver_t *resolver; /* resolver */ ngx_resolver_t *resolver; /* resolver */
+40 -3
View File
@@ -1959,7 +1959,7 @@ ngx_http_file_cache_manager(void *data)
{ {
ngx_http_file_cache_t *cache = data; ngx_http_file_cache_t *cache = data;
off_t size; off_t size, free;
time_t wait; time_t wait;
ngx_msec_t elapsed, next; ngx_msec_t elapsed, next;
ngx_uint_t count, watermark; ngx_uint_t count, watermark;
@@ -1988,7 +1988,19 @@ ngx_http_file_cache_manager(void *data)
size, count, (ngx_int_t) watermark); size, count, (ngx_int_t) watermark);
if (size < cache->max_size && count < watermark) { if (size < cache->max_size && count < watermark) {
break;
if (!cache->min_free) {
break;
}
free = ngx_fs_available(cache->path->name.data);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
"http file cache free: %O", free);
if (free > cache->min_free) {
break;
}
} }
wait = ngx_http_file_cache_forced_expire(cache); wait = ngx_http_file_cache_forced_expire(cache);
@@ -2304,7 +2316,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{ {
char *confp = conf; char *confp = conf;
off_t max_size; off_t max_size, min_free;
u_char *last, *p; u_char *last, *p;
time_t inactive; time_t inactive;
ssize_t size; ssize_t size;
@@ -2341,6 +2353,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
name.len = 0; name.len = 0;
size = 0; size = 0;
max_size = NGX_MAX_OFF_T_VALUE; max_size = NGX_MAX_OFF_T_VALUE;
min_free = 0;
value = cf->args->elts; value = cf->args->elts;
@@ -2476,6 +2489,29 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue; continue;
} }
if (ngx_strncmp(value[i].data, "min_free=", 9) == 0) {
#if (NGX_WIN32 || NGX_HAVE_STATFS || NGX_HAVE_STATVFS)
s.len = value[i].len - 9;
s.data = value[i].data + 9;
min_free = ngx_parse_offset(&s);
if (min_free < 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid min_free value \"%V\"", &value[i]);
return NGX_CONF_ERROR;
}
#else
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"min_free is not supported "
"on this platform, ignored");
#endif
continue;
}
if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) { if (ngx_strncmp(value[i].data, "loader_files=", 13) == 0) {
loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13); loader_files = ngx_atoi(value[i].data + 13, value[i].len - 13);
@@ -2607,6 +2643,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
cache->inactive = inactive; cache->inactive = inactive;
cache->max_size = max_size; cache->max_size = max_size;
cache->min_free = min_free;
caches = (ngx_array_t *) (confp + cmd->offset); caches = (ngx_array_t *) (confp + cmd->offset);
+49 -32
View File
@@ -131,7 +131,7 @@ ngx_http_header_t ngx_http_headers_in[] = {
{ ngx_string("Transfer-Encoding"), { ngx_string("Transfer-Encoding"),
offsetof(ngx_http_headers_in_t, transfer_encoding), offsetof(ngx_http_headers_in_t, transfer_encoding),
ngx_http_process_header_line }, ngx_http_process_unique_header_line },
{ ngx_string("TE"), { ngx_string("TE"),
offsetof(ngx_http_headers_in_t, te), offsetof(ngx_http_headers_in_t, te),
@@ -748,6 +748,8 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
return; return;
} }
ngx_reusable_connection(c, 0);
rc = ngx_ssl_handshake(c); rc = ngx_ssl_handshake(c);
if (rc == NGX_AGAIN) { if (rc == NGX_AGAIN) {
@@ -756,8 +758,6 @@ ngx_http_ssl_handshake(ngx_event_t *rev)
ngx_add_timer(rev, c->listening->post_accept_timeout); ngx_add_timer(rev, c->listening->post_accept_timeout);
} }
ngx_reusable_connection(c, 0);
c->ssl->handler = ngx_http_ssl_handshake_handler; c->ssl->handler = ngx_http_ssl_handshake_handler;
return; return;
} }
@@ -1654,6 +1654,12 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http large header copy: %uz", r->header_in->pos - old); "http large header copy: %uz", r->header_in->pos - old);
if (r->header_in->pos - old > b->end - b->start) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"too large header to copy");
return NGX_ERROR;
}
new = b->start; new = b->start;
ngx_memcpy(new, old, r->header_in->pos - old); ngx_memcpy(new, old, r->header_in->pos - old);
@@ -1762,10 +1768,18 @@ ngx_http_process_host(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_int_t rc; ngx_int_t rc;
ngx_str_t host; ngx_str_t host;
if (r->headers_in.host == NULL) { if (r->headers_in.host) {
r->headers_in.host = h; ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent duplicate host header: \"%V: %V\", "
"previous value: \"%V: %V\"",
&h->key, &h->value, &r->headers_in.host->key,
&r->headers_in.host->value);
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
} }
r->headers_in.host = h;
host = h->value; host = h->value;
rc = ngx_http_validate_host(&host, r->pool, 0); rc = ngx_http_validate_host(&host, r->pool, 0);
@@ -1962,10 +1976,7 @@ ngx_http_process_request_header(ngx_http_request_t *r)
r->headers_in.content_length_n = -1; r->headers_in.content_length_n = -1;
r->headers_in.chunked = 1; r->headers_in.chunked = 1;
} else if (r->headers_in.transfer_encoding->value.len != 8 } else {
|| ngx_strncasecmp(r->headers_in.transfer_encoding->value.data,
(u_char *) "identity", 8) != 0)
{
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent unknown \"Transfer-Encoding\": \"%V\"", "client sent unknown \"Transfer-Encoding\": \"%V\"",
&r->headers_in.transfer_encoding->value); &r->headers_in.transfer_encoding->value);
@@ -1998,6 +2009,7 @@ ngx_http_process_request(ngx_http_request_t *r)
if (r->http_connection->ssl) { if (r->http_connection->ssl) {
long rc; long rc;
X509 *cert; X509 *cert;
const char *s;
ngx_http_ssl_srv_conf_t *sscf; ngx_http_ssl_srv_conf_t *sscf;
if (c->ssl == NULL) { if (c->ssl == NULL) {
@@ -2046,6 +2058,17 @@ ngx_http_process_request(ngx_http_request_t *r)
X509_free(cert); X509_free(cert);
} }
if (ngx_ssl_ocsp_get_status(c, &s) != NGX_OK) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client SSL certificate verify error: %s", s);
ngx_ssl_remove_cached_session(c->ssl->session_ctx,
(SSL_get0_session(c->ssl->connection)));
ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR);
return;
}
} }
} }
@@ -2497,26 +2520,6 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
} }
if (r != r->main) { 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) { if (r->buffered || r->postponed) {
@@ -2529,11 +2532,12 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
pr = r->parent; pr = r->parent;
if (r == c->data) { if (r == c->data || r->background) {
r->main->count--;
if (!r->logged) { if (!r->logged) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->log_subrequest) { if (clcf->log_subrequest) {
ngx_http_log_request(r); ngx_http_log_request(r);
} }
@@ -2548,6 +2552,13 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
r->done = 1; r->done = 1;
if (r->background) {
ngx_http_finalize_connection(r);
return;
}
r->main->count--;
if (pr->postponed && pr->postponed->request == r) { if (pr->postponed && pr->postponed->request == r) {
pr->postponed = pr->postponed->next; pr->postponed = pr->postponed->next;
} }
@@ -2995,6 +3006,12 @@ closed:
rev->error = 1; rev->error = 1;
} }
#if (NGX_HTTP_SSL)
if (c->ssl) {
c->ssl->no_send_shutdown = 1;
}
#endif
ngx_log_error(NGX_LOG_INFO, c->log, err, ngx_log_error(NGX_LOG_INFO, c->log, err,
"client prematurely closed connection"); "client prematurely closed connection");
+2 -2
View File
@@ -510,9 +510,9 @@ struct ngx_http_request_s {
/* /*
* instead of using the request context data in * instead of using the request context data in
* ngx_http_limit_conn_module and ngx_http_limit_req_module * ngx_http_limit_conn_module and ngx_http_limit_req_module
* we use the single bits in the request structure * we use the bit fields in the request structure
*/ */
unsigned limit_conn_set:1; unsigned limit_conn_status:2;
unsigned limit_req_status:3; unsigned limit_req_status:3;
unsigned limit_rate_set:1; unsigned limit_rate_set:1;
+148 -51
View File
@@ -12,6 +12,8 @@
static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r,
ngx_buf_t *buf);
static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
@@ -282,28 +284,12 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
for ( ;; ) { for ( ;; ) {
if (rb->buf->last == rb->buf->end) { if (rb->buf->last == rb->buf->end) {
if (rb->buf->pos != rb->buf->last) { /* update chains */
/* pass buffer to request body filter chain */ rc = ngx_http_request_body_filter(r, NULL);
out.buf = rb->buf; if (rc != NGX_OK) {
out.next = NULL; return rc;
rc = ngx_http_request_body_filter(r, &out);
if (rc != NGX_OK) {
return rc;
}
} else {
/* update chains */
rc = ngx_http_request_body_filter(r, NULL);
if (rc != NGX_OK) {
return rc;
}
} }
if (rb->busy != NULL) { if (rb->busy != NULL) {
@@ -355,17 +341,15 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
rb->buf->last += n; rb->buf->last += n;
r->request_length += n; r->request_length += n;
if (n == rest) { /* pass buffer to request body filter chain */
/* pass buffer to request body filter chain */
out.buf = rb->buf; out.buf = rb->buf;
out.next = NULL; out.next = NULL;
rc = ngx_http_request_body_filter(r, &out); rc = ngx_http_request_body_filter(r, &out);
if (rc != NGX_OK) { if (rc != NGX_OK) {
return rc; return rc;
}
} }
if (rb->rest == 0) { if (rb->rest == 0) {
@@ -386,21 +370,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
if (!c->read->ready) { if (!c->read->ready) {
if (r->request_body_no_buffering
&& rb->buf->pos != rb->buf->last)
{
/* pass buffer to request body filter chain */
out.buf = rb->buf;
out.next = NULL;
rc = ngx_http_request_body_filter(r, &out);
if (rc != NGX_OK) {
return rc;
}
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
ngx_add_timer(c->read, clcf->client_body_timeout); ngx_add_timer(c->read, clcf->client_body_timeout);
@@ -412,6 +381,10 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
} }
} }
if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (c->read->timer_set) { if (c->read->timer_set) {
ngx_del_timer(c->read); ngx_del_timer(c->read);
} }
@@ -425,6 +398,88 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
} }
static ngx_int_t
ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
{
size_t n;
ngx_buf_t *b;
ngx_chain_t *cl;
ngx_http_connection_t *hc;
ngx_http_core_srv_conf_t *cscf;
b = r->header_in;
n = buf->last - buf->pos;
if (buf == b || n == 0) {
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http body pipelined header: %uz", n);
/*
* if there is a pipelined request in the client body buffer,
* copy it to the r->header_in buffer if there is enough room,
* or allocate a large client header buffer
*/
if (n > (size_t) (b->end - b->last)) {
hc = r->http_connection;
if (hc->free) {
cl = hc->free;
hc->free = cl->next;
b = cl->buf;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http large header free: %p %uz",
b->pos, b->end - b->last);
} else {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
b = ngx_create_temp_buf(r->connection->pool,
cscf->large_client_header_buffers.size);
if (b == NULL) {
return NGX_ERROR;
}
cl = ngx_alloc_chain_link(r->connection->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http large header alloc: %p %uz",
b->pos, b->end - b->last);
}
cl->next = hc->busy;
hc->busy = cl;
hc->nbusy++;
r->header_in = b;
if (n > (size_t) (b->end - b->last)) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"too large pipelined header after reading body");
return NGX_ERROR;
}
}
ngx_memcpy(b->last, buf->pos, n);
b->last += n;
r->request_length -= n;
return NGX_OK;
}
static ngx_int_t static ngx_int_t
ngx_http_write_request_body(ngx_http_request_t *r) ngx_http_write_request_body(ngx_http_request_t *r)
{ {
@@ -670,8 +725,7 @@ ngx_http_read_discarded_request_body(ngx_http_request_t *r)
for ( ;; ) { for ( ;; ) {
if (r->headers_in.content_length_n == 0) { if (r->headers_in.content_length_n == 0) {
r->read_event_handler = ngx_http_block_reading; break;
return NGX_OK;
} }
if (!r->connection->read->ready) { if (!r->connection->read->ready) {
@@ -705,15 +759,24 @@ ngx_http_read_discarded_request_body(ngx_http_request_t *r)
return rc; return rc;
} }
} }
if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
r->read_event_handler = ngx_http_block_reading;
return NGX_OK;
} }
static ngx_int_t static ngx_int_t
ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
{ {
size_t size; size_t size;
ngx_int_t rc; ngx_int_t rc;
ngx_http_request_body_t *rb; ngx_http_request_body_t *rb;
ngx_http_core_srv_conf_t *cscf;
if (r->headers_in.chunked) { if (r->headers_in.chunked) {
@@ -768,7 +831,10 @@ ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
/* set amount of data we want to see next time */ /* set amount of data we want to see next time */
r->headers_in.content_length_n = rb->chunked->length; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->headers_in.content_length_n = ngx_max(rb->chunked->length,
(off_t) cscf->large_client_header_buffers.size);
break; break;
} }
@@ -936,6 +1002,7 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_chain_t *cl, *out, *tl, **ll; ngx_chain_t *cl, *out, *tl, **ll;
ngx_http_request_body_t *rb; ngx_http_request_body_t *rb;
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
rb = r->request_body; rb = r->request_body;
@@ -949,8 +1016,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
} }
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->headers_in.content_length_n = 0; r->headers_in.content_length_n = 0;
rb->rest = 3; rb->rest = cscf->large_client_header_buffers.size;
} }
out = NULL; out = NULL;
@@ -958,6 +1027,8 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
for (cl = in; cl; cl = cl->next) { for (cl = in; cl; cl = cl->next) {
b = NULL;
for ( ;; ) { for ( ;; ) {
ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
@@ -992,6 +1063,29 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
} }
if (b
&& rb->chunked->size <= 128
&& cl->buf->last - cl->buf->pos >= rb->chunked->size)
{
r->headers_in.content_length_n += rb->chunked->size;
if (rb->chunked->size < 8) {
while (rb->chunked->size) {
*b->last++ = *cl->buf->pos++;
rb->chunked->size--;
}
} else {
ngx_memmove(b->last, cl->buf->pos, rb->chunked->size);
b->last += rb->chunked->size;
cl->buf->pos += rb->chunked->size;
rb->chunked->size = 0;
}
continue;
}
tl = ngx_chain_get_free_buf(r->pool, &rb->free); tl = ngx_chain_get_free_buf(r->pool, &rb->free);
if (tl == NULL) { if (tl == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -1057,7 +1151,10 @@ ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
/* set rb->rest, amount of data we want to see next time */ /* set rb->rest, amount of data we want to see next time */
rb->rest = rb->chunked->length; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
rb->rest = ngx_max(rb->chunked->length,
(off_t) cscf->large_client_header_buffers.size);
break; break;
} }
+8 -1
View File
@@ -1470,7 +1470,14 @@ ngx_http_script_return_code(ngx_http_script_engine_t *e)
void void
ngx_http_script_break_code(ngx_http_script_engine_t *e) ngx_http_script_break_code(ngx_http_script_engine_t *e)
{ {
e->request->uri_changed = 0; ngx_http_request_t *r;
r = e->request;
if (r->uri_changed) {
r->valid_location = 0;
r->uri_changed = 0;
}
e->ip = ngx_http_script_exit; e->ip = ngx_http_script_exit;
} }
+7
View File
@@ -33,6 +33,7 @@ static u_char ngx_http_error_build_tail[] =
static u_char ngx_http_error_tail[] = static u_char ngx_http_error_tail[] =
"<hr><center>" NGINX_SERVER "</center>" CRLF
"</body>" CRLF "</body>" CRLF
"</html>" CRLF "</html>" CRLF
; ;
@@ -622,6 +623,12 @@ ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page)
return ngx_http_named_location(r, &uri); return ngx_http_named_location(r, &uri);
} }
r->expect_tested = 1;
if (ngx_http_discard_request_body(r) != NGX_OK) {
r->keepalive = 0;
}
location = ngx_list_push(&r->headers_out.headers); location = ngx_list_push(&r->headers_out.headers);
if (location == NULL) { if (location == NULL) {
+19 -7
View File
@@ -77,9 +77,6 @@ static void
static void static void
ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r, ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
ngx_uint_t do_write); ngx_uint_t do_write);
static ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
ssize_t bytes);
#if (NGX_THREADS) #if (NGX_THREADS)
static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task, static ngx_int_t ngx_http_upstream_thread_handler(ngx_thread_task_t *task,
ngx_file_t *file); ngx_file_t *file);
@@ -1919,6 +1916,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->keepalive = 0; u->keepalive = 0;
u->upgrade = 0; u->upgrade = 0;
u->error = 0;
ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
u->headers_in.content_length_n = -1; u->headers_in.content_length_n = -1;
@@ -2475,7 +2473,7 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
#if (NGX_HTTP_CACHE) #if (NGX_HTTP_CACHE)
if (u->cache_status == NGX_HTTP_CACHE_EXPIRED if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
&& ((u->conf->cache_use_stale & un->mask) || r->cache->stale_error)) && (u->conf->cache_use_stale & un->mask))
{ {
ngx_int_t rc; ngx_int_t rc;
@@ -2502,6 +2500,8 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
} }
#endif #endif
break;
} }
#if (NGX_HTTP_CACHE) #if (NGX_HTTP_CACHE)
@@ -3625,7 +3625,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
return; return;
} }
if (upstream->read->error) { if (upstream->read->error || u->error) {
ngx_http_upstream_finalize_request(r, u, ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_BAD_GATEWAY); NGX_HTTP_BAD_GATEWAY);
return; return;
@@ -3703,14 +3703,14 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
} }
static ngx_int_t ngx_int_t
ngx_http_upstream_non_buffered_filter_init(void *data) ngx_http_upstream_non_buffered_filter_init(void *data)
{ {
return NGX_OK; return NGX_OK;
} }
static ngx_int_t ngx_int_t
ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes) ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
{ {
ngx_http_request_t *r = data; ngx_http_request_t *r = data;
@@ -3746,6 +3746,18 @@ ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes)
return NGX_OK; return NGX_OK;
} }
if (bytes > u->length) {
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
"upstream sent more data than specified in "
"\"Content-Length\" header");
cl->buf->last = cl->buf->pos + u->length;
u->length = 0;
return NGX_OK;
}
u->length -= bytes; u->length -= bytes;
return NGX_OK; return NGX_OK;
+3
View File
@@ -391,6 +391,7 @@ struct ngx_http_upstream_s {
unsigned buffering:1; unsigned buffering:1;
unsigned keepalive:1; unsigned keepalive:1;
unsigned upgrade:1; unsigned upgrade:1;
unsigned error:1;
unsigned request_sent:1; unsigned request_sent:1;
unsigned request_body_sent:1; unsigned request_body_sent:1;
@@ -414,6 +415,8 @@ typedef struct {
ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r); ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r);
void ngx_http_upstream_init(ngx_http_request_t *r); void ngx_http_upstream_init(ngx_http_request_t *r);
ngx_int_t ngx_http_upstream_non_buffered_filter_init(void *data);
ngx_int_t ngx_http_upstream_non_buffered_filter(void *data, ssize_t bytes);
ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
ngx_url_t *u, ngx_uint_t flags); ngx_url_t *u, ngx_uint_t flags);
char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, char *ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+1 -1
View File
@@ -1075,7 +1075,7 @@ ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
len = name->len - (sizeof("arg_") - 1); len = name->len - (sizeof("arg_") - 1);
arg = name->data + sizeof("arg_") - 1; arg = name->data + sizeof("arg_") - 1;
if (ngx_http_arg(r, arg, len, &value) != NGX_OK) { if (len == 0 || ngx_http_arg(r, arg, len, &value) != NGX_OK) {
v->not_found = 1; v->not_found = 1;
return NGX_OK; return NGX_OK;
} }
+154 -20
View File
@@ -60,6 +60,8 @@ typedef struct {
static void ngx_http_v2_read_handler(ngx_event_t *rev); static void ngx_http_v2_read_handler(ngx_event_t *rev);
static void ngx_http_v2_write_handler(ngx_event_t *wev); static void ngx_http_v2_write_handler(ngx_event_t *wev);
static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c); static void ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c);
static void ngx_http_v2_lingering_close(ngx_http_v2_connection_t *h2c);
static void ngx_http_v2_lingering_close_handler(ngx_event_t *rev);
static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, static u_char *ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c,
u_char *pos, u_char *end); u_char *pos, u_char *end);
@@ -178,6 +180,7 @@ static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
ngx_http_v2_stream_t *stream, ngx_uint_t status); ngx_http_v2_stream_t *stream, ngx_uint_t status);
static void ngx_http_v2_close_stream_handler(ngx_event_t *ev); static void ngx_http_v2_close_stream_handler(ngx_event_t *ev);
static void ngx_http_v2_retry_close_stream_handler(ngx_event_t *ev);
static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev); static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev);
static void ngx_http_v2_idle_handler(ngx_event_t *rev); static void ngx_http_v2_idle_handler(ngx_event_t *rev);
static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c, static void ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
@@ -474,6 +477,7 @@ ngx_http_v2_write_handler(ngx_event_t *wev)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http2 write event timed out"); "http2 write event timed out");
c->error = 1; c->error = 1;
c->timedout = 1;
ngx_http_v2_finalize_connection(h2c, 0); ngx_http_v2_finalize_connection(h2c, 0);
return; return;
} }
@@ -662,7 +666,7 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
} }
if (h2c->goaway) { if (h2c->goaway) {
ngx_http_close_connection(c); ngx_http_v2_lingering_close(h2c);
return; return;
} }
@@ -700,6 +704,113 @@ ngx_http_v2_handle_connection(ngx_http_v2_connection_t *h2c)
} }
static void
ngx_http_v2_lingering_close(ngx_http_v2_connection_t *h2c)
{
ngx_event_t *rev, *wev;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
c = h2c->connection;
clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
ngx_http_core_module);
if (clcf->lingering_close == NGX_HTTP_LINGERING_OFF) {
ngx_http_close_connection(c);
return;
}
rev = c->read;
rev->handler = ngx_http_v2_lingering_close_handler;
h2c->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000);
ngx_add_timer(rev, clcf->lingering_timeout);
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
wev = c->write;
wev->handler = ngx_http_empty_handler;
if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
}
if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
ngx_connection_error(c, ngx_socket_errno,
ngx_shutdown_socket_n " failed");
ngx_http_close_connection(c);
return;
}
if (rev->ready) {
ngx_http_v2_lingering_close_handler(rev);
}
}
static void
ngx_http_v2_lingering_close_handler(ngx_event_t *rev)
{
ssize_t n;
ngx_msec_t timer;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
ngx_http_v2_connection_t *h2c;
u_char buffer[NGX_HTTP_LINGERING_BUFFER_SIZE];
c = rev->data;
h2c = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http2 lingering close handler");
if (rev->timedout) {
ngx_http_close_connection(c);
return;
}
timer = (ngx_msec_t) h2c->lingering_time - (ngx_msec_t) ngx_time();
if ((ngx_msec_int_t) timer <= 0) {
ngx_http_close_connection(c);
return;
}
do {
n = c->recv(c, buffer, NGX_HTTP_LINGERING_BUFFER_SIZE);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "lingering read: %z", n);
if (n == NGX_ERROR || n == 0) {
ngx_http_close_connection(c);
return;
}
} while (rev->ready);
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_close_connection(c);
return;
}
clcf = ngx_http_get_module_loc_conf(h2c->http_connection->conf_ctx,
ngx_http_core_module);
timer *= 1000;
if (timer > clcf->lingering_timeout) {
timer = clcf->lingering_timeout;
}
ngx_add_timer(rev, timer);
}
static u_char * static u_char *
ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos, ngx_http_v2_state_proxy_protocol(ngx_http_v2_connection_t *h2c, u_char *pos,
u_char *end) u_char *end)
@@ -732,9 +843,8 @@ ngx_http_v2_state_preface(ngx_http_v2_connection_t *h2c, u_char *pos,
} }
if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"invalid http2 connection preface \"%*s\"", "invalid connection preface");
sizeof(preface) - 1, pos);
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
} }
@@ -755,9 +865,8 @@ ngx_http_v2_state_preface_end(ngx_http_v2_connection_t *h2c, u_char *pos,
} }
if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) { if (ngx_memcmp(pos, preface, sizeof(preface) - 1) != 0) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"invalid http2 connection preface \"%*s\"", "invalid connection preface");
sizeof(preface) - 1, pos);
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
} }
@@ -1720,8 +1829,13 @@ ngx_http_v2_state_header_complete(ngx_http_v2_connection_t *h2c, u_char *pos,
ngx_http_v2_stream_t *stream; ngx_http_v2_stream_t *stream;
if (h2c->state.length) { if (h2c->state.length) {
h2c->state.handler = ngx_http_v2_state_header_block; if (end - pos > 0) {
return pos; h2c->state.handler = ngx_http_v2_state_header_block;
return pos;
}
return ngx_http_v2_state_headers_save(h2c, pos, end,
ngx_http_v2_state_header_block);
} }
if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) { if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) {
@@ -2475,10 +2589,6 @@ ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c,
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 state connection error"); "http2 state connection error");
if (err == NGX_HTTP_V2_INTERNAL_ERROR) {
ngx_debug_point();
}
ngx_http_v2_finalize_connection(h2c, err); ngx_http_v2_finalize_connection(h2c, err);
return NULL; return NULL;
@@ -4298,8 +4408,9 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
fc = stream->request->connection; fc = stream->request->connection;
if (stream->queued) { if (stream->queued) {
fc->write->handler = ngx_http_v2_close_stream_handler; fc->error = 1;
fc->read->handler = ngx_http_empty_handler; fc->write->handler = ngx_http_v2_retry_close_stream_handler;
fc->read->handler = ngx_http_v2_retry_close_stream_handler;
return; return;
} }
@@ -4421,6 +4532,22 @@ ngx_http_v2_close_stream_handler(ngx_event_t *ev)
} }
static void
ngx_http_v2_retry_close_stream_handler(ngx_event_t *ev)
{
ngx_connection_t *fc;
ngx_http_request_t *r;
fc = ev->data;
r = fc->data;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
"http2 retry close stream handler");
ngx_http_v2_close_stream(r->stream, 0);
}
static void static void
ngx_http_v2_handle_connection_handler(ngx_event_t *rev) ngx_http_v2_handle_connection_handler(ngx_event_t *rev)
{ {
@@ -4534,16 +4661,15 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
h2c->blocked = 1; h2c->blocked = 1;
if (!c->error && !h2c->goaway) { if (!c->error && !h2c->goaway) {
h2c->goaway = 1;
if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) { if (ngx_http_v2_send_goaway(h2c, status) != NGX_ERROR) {
(void) ngx_http_v2_send_output_queue(h2c); (void) ngx_http_v2_send_output_queue(h2c);
} }
} }
c->error = 1;
if (!h2c->processing && !h2c->pushing) { if (!h2c->processing && !h2c->pushing) {
ngx_http_close_connection(c); goto done;
return;
} }
c->read->handler = ngx_http_empty_handler; c->read->handler = ngx_http_empty_handler;
@@ -4591,10 +4717,18 @@ ngx_http_v2_finalize_connection(ngx_http_v2_connection_t *h2c,
h2c->blocked = 0; h2c->blocked = 0;
if (h2c->processing || h2c->pushing) { if (h2c->processing || h2c->pushing) {
c->error = 1;
return; return;
} }
ngx_http_close_connection(c); done:
if (c->error) {
ngx_http_close_connection(c);
return;
}
ngx_http_v2_lingering_close(h2c);
} }
+2
View File
@@ -207,6 +207,8 @@ struct ngx_http_v2_connection_s {
ngx_uint_t last_sid; ngx_uint_t last_sid;
ngx_uint_t last_push; ngx_uint_t last_push;
time_t lingering_time;
unsigned closed_nodes:8; unsigned closed_nodes:8;
unsigned settings_ack:1; unsigned settings_ack:1;
unsigned table_update:1; unsigned table_update:1;
+45
View File
@@ -875,9 +875,28 @@ ngx_fs_bsize(u_char *name)
return 512; return 512;
} }
#if (NGX_LINUX)
if ((size_t) fs.f_bsize > ngx_pagesize) {
return 512;
}
#endif
return (size_t) fs.f_bsize; return (size_t) fs.f_bsize;
} }
off_t
ngx_fs_available(u_char *name)
{
struct statfs fs;
if (statfs((char *) name, &fs) == -1) {
return NGX_MAX_OFF_T_VALUE;
}
return (off_t) fs.f_bavail * fs.f_bsize;
}
#elif (NGX_HAVE_STATVFS) #elif (NGX_HAVE_STATVFS)
size_t size_t
@@ -893,9 +912,28 @@ ngx_fs_bsize(u_char *name)
return 512; return 512;
} }
#if (NGX_LINUX)
if ((size_t) fs.f_frsize > ngx_pagesize) {
return 512;
}
#endif
return (size_t) fs.f_frsize; return (size_t) fs.f_frsize;
} }
off_t
ngx_fs_available(u_char *name)
{
struct statvfs fs;
if (statvfs((char *) name, &fs) == -1) {
return NGX_MAX_OFF_T_VALUE;
}
return (off_t) fs.f_bavail * fs.f_frsize;
}
#else #else
size_t size_t
@@ -904,4 +942,11 @@ ngx_fs_bsize(u_char *name)
return 512; return 512;
} }
off_t
ngx_fs_available(u_char *name)
{
return NGX_MAX_OFF_T_VALUE;
}
#endif #endif
+5 -1
View File
@@ -185,7 +185,10 @@ ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s);
#define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) #define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR)
#define ngx_file_access(sb) ((sb)->st_mode & 0777) #define ngx_file_access(sb) ((sb)->st_mode & 0777)
#define ngx_file_size(sb) (sb)->st_size #define ngx_file_size(sb) (sb)->st_size
#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512) #define ngx_file_fs_size(sb) \
(((sb)->st_blocks * 512 > (sb)->st_size \
&& (sb)->st_blocks * 512 < (sb)->st_size + 8 * (sb)->st_blksize) \
? (sb)->st_blocks * 512 : (sb)->st_size)
#define ngx_file_mtime(sb) (sb)->st_mtime #define ngx_file_mtime(sb) (sb)->st_mtime
#define ngx_file_uniq(sb) (sb)->st_ino #define ngx_file_uniq(sb) (sb)->st_ino
@@ -346,6 +349,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
#endif #endif
size_t ngx_fs_bsize(u_char *name); size_t ngx_fs_bsize(u_char *name);
off_t ngx_fs_available(u_char *name);
#if (NGX_HAVE_OPENAT) #if (NGX_HAVE_OPENAT)
+2 -12
View File
@@ -77,12 +77,11 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
u_char *p; u_char *p;
size_t size; size_t size;
ngx_int_t i; ngx_int_t i;
ngx_uint_t n, sigio; ngx_uint_t sigio;
sigset_t set; sigset_t set;
struct itimerval itv; struct itimerval itv;
ngx_uint_t live; ngx_uint_t live;
ngx_msec_t delay; ngx_msec_t delay;
ngx_listening_t *ls;
ngx_core_conf_t *ccf; ngx_core_conf_t *ccf;
sigemptyset(&set); sigemptyset(&set);
@@ -204,16 +203,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
if (ngx_quit) { if (ngx_quit) {
ngx_signal_worker_processes(cycle, ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
ngx_close_listening_sockets(cycle);
ls = cycle->listening.elts;
for (n = 0; n < cycle->listening.nelts; n++) {
if (ngx_close_socket(ls[n].fd) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
ngx_close_socket_n " %V failed",
&ls[n].addr_text);
}
}
cycle->listening.nelts = 0;
continue; continue;
} }
+7
View File
@@ -189,6 +189,13 @@ ngx_udp_output_chain_to_iovec(ngx_iovec_t *vec, ngx_chain_t *in, ngx_log_t *log)
return cl; return cl;
} }
/* zero-sized datagram; pretend to have at least 1 iov */
if (n == 0) {
iov = &vec->iovs[n++];
iov->iov_base = NULL;
iov->iov_len = 0;
}
vec->count = n; vec->count = n;
vec->size = total; vec->size = total;
+13
View File
@@ -658,6 +658,19 @@ ngx_fs_bsize(u_char *name)
} }
off_t
ngx_fs_available(u_char *name)
{
ULARGE_INTEGER navail;
if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) {
return NGX_MAX_OFF_T_VALUE;
}
return (off_t) navail.QuadPart;
}
static ngx_int_t static ngx_int_t
ngx_win32_check_filename(u_char *name, u_short *u, size_t len) ngx_win32_check_filename(u_char *name, u_short *u, size_t len)
{ {
+1
View File
@@ -259,6 +259,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd);
#define ngx_directio_off_n "ngx_directio_off_n" #define ngx_directio_off_n "ngx_directio_off_n"
size_t ngx_fs_bsize(u_char *name); size_t ngx_fs_bsize(u_char *name);
off_t ngx_fs_available(u_char *name);
#define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE) #define ngx_stdout GetStdHandle(STD_OUTPUT_HANDLE)
+2
View File
@@ -226,6 +226,8 @@ struct ngx_stream_session_s {
unsigned stat_processing:1; unsigned stat_processing:1;
unsigned health_check:1; unsigned health_check:1;
unsigned limit_conn_status:2;
}; };
+138 -47
View File
@@ -10,35 +10,48 @@
#include <ngx_stream.h> #include <ngx_stream.h>
#define NGX_STREAM_LIMIT_CONN_PASSED 1
#define NGX_STREAM_LIMIT_CONN_REJECTED 2
#define NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN 3
typedef struct { typedef struct {
u_char color; u_char color;
u_char len; u_char len;
u_short conn; u_short conn;
u_char data[1]; u_char data[1];
} ngx_stream_limit_conn_node_t; } ngx_stream_limit_conn_node_t;
typedef struct { typedef struct {
ngx_shm_zone_t *shm_zone; ngx_shm_zone_t *shm_zone;
ngx_rbtree_node_t *node; ngx_rbtree_node_t *node;
} ngx_stream_limit_conn_cleanup_t; } ngx_stream_limit_conn_cleanup_t;
typedef struct { typedef struct {
ngx_rbtree_t *rbtree; ngx_rbtree_t rbtree;
ngx_stream_complex_value_t key; ngx_rbtree_node_t sentinel;
} ngx_stream_limit_conn_shctx_t;
typedef struct {
ngx_stream_limit_conn_shctx_t *sh;
ngx_slab_pool_t *shpool;
ngx_stream_complex_value_t key;
} ngx_stream_limit_conn_ctx_t; } ngx_stream_limit_conn_ctx_t;
typedef struct { typedef struct {
ngx_shm_zone_t *shm_zone; ngx_shm_zone_t *shm_zone;
ngx_uint_t conn; ngx_uint_t conn;
} ngx_stream_limit_conn_limit_t; } ngx_stream_limit_conn_limit_t;
typedef struct { typedef struct {
ngx_array_t limits; ngx_array_t limits;
ngx_uint_t log_level; ngx_uint_t log_level;
ngx_flag_t dry_run;
} ngx_stream_limit_conn_conf_t; } ngx_stream_limit_conn_conf_t;
@@ -47,6 +60,8 @@ static ngx_rbtree_node_t *ngx_stream_limit_conn_lookup(ngx_rbtree_t *rbtree,
static void ngx_stream_limit_conn_cleanup(void *data); static void ngx_stream_limit_conn_cleanup(void *data);
static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool); static ngx_inline void ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool);
static ngx_int_t ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data);
static void *ngx_stream_limit_conn_create_conf(ngx_conf_t *cf); static void *ngx_stream_limit_conn_create_conf(ngx_conf_t *cf);
static char *ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, static char *ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent,
void *child); void *child);
@@ -54,6 +69,7 @@ static char *ngx_stream_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static ngx_int_t ngx_stream_limit_conn_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_stream_limit_conn_init(ngx_conf_t *cf); static ngx_int_t ngx_stream_limit_conn_init(ngx_conf_t *cf);
@@ -89,12 +105,19 @@ static ngx_command_t ngx_stream_limit_conn_commands[] = {
offsetof(ngx_stream_limit_conn_conf_t, log_level), offsetof(ngx_stream_limit_conn_conf_t, log_level),
&ngx_stream_limit_conn_log_levels }, &ngx_stream_limit_conn_log_levels },
{ ngx_string("limit_conn_dry_run"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_STREAM_SRV_CONF_OFFSET,
offsetof(ngx_stream_limit_conn_conf_t, dry_run),
NULL },
ngx_null_command ngx_null_command
}; };
static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = { static ngx_stream_module_t ngx_stream_limit_conn_module_ctx = {
NULL, /* preconfiguration */ ngx_stream_limit_conn_add_variables, /* preconfiguration */
ngx_stream_limit_conn_init, /* postconfiguration */ ngx_stream_limit_conn_init, /* postconfiguration */
NULL, /* create main configuration */ NULL, /* create main configuration */
@@ -121,6 +144,22 @@ ngx_module_t ngx_stream_limit_conn_module = {
}; };
static ngx_stream_variable_t ngx_stream_limit_conn_vars[] = {
{ ngx_string("limit_conn_status"), NULL,
ngx_stream_limit_conn_status_variable, 0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
ngx_stream_null_variable
};
static ngx_str_t ngx_stream_limit_conn_status[] = {
ngx_string("PASSED"),
ngx_string("REJECTED"),
ngx_string("REJECTED_DRY_RUN")
};
static ngx_int_t static ngx_int_t
ngx_stream_limit_conn_handler(ngx_stream_session_t *s) ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
{ {
@@ -128,7 +167,6 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
uint32_t hash; uint32_t hash;
ngx_str_t key; ngx_str_t key;
ngx_uint_t i; ngx_uint_t i;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node; ngx_rbtree_node_t *node;
ngx_pool_cleanup_t *cln; ngx_pool_cleanup_t *cln;
ngx_stream_limit_conn_ctx_t *ctx; ngx_stream_limit_conn_ctx_t *ctx;
@@ -159,13 +197,13 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
continue; continue;
} }
s->limit_conn_status = NGX_STREAM_LIMIT_CONN_PASSED;
hash = ngx_crc32_short(key.data, key.len); hash = ngx_crc32_short(key.data, key.len);
shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; ngx_shmtx_lock(&ctx->shpool->mutex);
ngx_shmtx_lock(&shpool->mutex); node = ngx_stream_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
node = ngx_stream_limit_conn_lookup(ctx->rbtree, &key, hash);
if (node == NULL) { if (node == NULL) {
@@ -173,11 +211,20 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
+ offsetof(ngx_stream_limit_conn_node_t, data) + offsetof(ngx_stream_limit_conn_node_t, data)
+ key.len; + key.len;
node = ngx_slab_alloc_locked(shpool, n); node = ngx_slab_alloc_locked(ctx->shpool, n);
if (node == NULL) { if (node == NULL) {
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_stream_limit_conn_cleanup_all(s->connection->pool); ngx_stream_limit_conn_cleanup_all(s->connection->pool);
if (lccf->dry_run) {
s->limit_conn_status =
NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN;
return NGX_DECLINED;
}
s->limit_conn_status = NGX_STREAM_LIMIT_CONN_REJECTED;
return NGX_STREAM_SERVICE_UNAVAILABLE; return NGX_STREAM_SERVICE_UNAVAILABLE;
} }
@@ -188,7 +235,7 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
lc->conn = 1; lc->conn = 1;
ngx_memcpy(lc->data, key.data, key.len); ngx_memcpy(lc->data, key.data, key.len);
ngx_rbtree_insert(ctx->rbtree, node); ngx_rbtree_insert(&ctx->sh->rbtree, node);
} else { } else {
@@ -196,13 +243,23 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
if ((ngx_uint_t) lc->conn >= limits[i].conn) { if ((ngx_uint_t) lc->conn >= limits[i].conn) {
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
ngx_log_error(lccf->log_level, s->connection->log, 0, ngx_log_error(lccf->log_level, s->connection->log, 0,
"limiting connections by zone \"%V\"", "limiting connections%s by zone \"%V\"",
lccf->dry_run ? ", dry run," : "",
&limits[i].shm_zone->shm.name); &limits[i].shm_zone->shm.name);
ngx_stream_limit_conn_cleanup_all(s->connection->pool); ngx_stream_limit_conn_cleanup_all(s->connection->pool);
if (lccf->dry_run) {
s->limit_conn_status =
NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN;
return NGX_DECLINED;
}
s->limit_conn_status = NGX_STREAM_LIMIT_CONN_REJECTED;
return NGX_STREAM_SERVICE_UNAVAILABLE; return NGX_STREAM_SERVICE_UNAVAILABLE;
} }
@@ -212,7 +269,7 @@ ngx_stream_limit_conn_handler(ngx_stream_session_t *s)
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
"limit conn: %08Xi %d", node->key, lc->conn); "limit conn: %08Xi %d", node->key, lc->conn);
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
cln = ngx_pool_cleanup_add(s->connection->pool, cln = ngx_pool_cleanup_add(s->connection->pool,
sizeof(ngx_stream_limit_conn_cleanup_t)); sizeof(ngx_stream_limit_conn_cleanup_t));
@@ -317,17 +374,15 @@ ngx_stream_limit_conn_cleanup(void *data)
{ {
ngx_stream_limit_conn_cleanup_t *lccln = data; ngx_stream_limit_conn_cleanup_t *lccln = data;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node; ngx_rbtree_node_t *node;
ngx_stream_limit_conn_ctx_t *ctx; ngx_stream_limit_conn_ctx_t *ctx;
ngx_stream_limit_conn_node_t *lc; ngx_stream_limit_conn_node_t *lc;
ctx = lccln->shm_zone->data; ctx = lccln->shm_zone->data;
shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
node = lccln->node; node = lccln->node;
lc = (ngx_stream_limit_conn_node_t *) &node->color; lc = (ngx_stream_limit_conn_node_t *) &node->color;
ngx_shmtx_lock(&shpool->mutex); ngx_shmtx_lock(&ctx->shpool->mutex);
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0, ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0,
"limit conn cleanup: %08Xi %d", node->key, lc->conn); "limit conn cleanup: %08Xi %d", node->key, lc->conn);
@@ -335,11 +390,11 @@ ngx_stream_limit_conn_cleanup(void *data)
lc->conn--; lc->conn--;
if (lc->conn == 0) { if (lc->conn == 0) {
ngx_rbtree_delete(ctx->rbtree, node); ngx_rbtree_delete(&ctx->sh->rbtree, node);
ngx_slab_free_locked(shpool, node); ngx_slab_free_locked(ctx->shpool, node);
} }
ngx_shmtx_unlock(&shpool->mutex); ngx_shmtx_unlock(&ctx->shpool->mutex);
} }
@@ -365,8 +420,6 @@ ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
ngx_stream_limit_conn_ctx_t *octx = data; ngx_stream_limit_conn_ctx_t *octx = data;
size_t len; size_t len;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *sentinel;
ngx_stream_limit_conn_ctx_t *ctx; ngx_stream_limit_conn_ctx_t *ctx;
ctx = shm_zone->data; ctx = shm_zone->data;
@@ -385,48 +438,64 @@ ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
return NGX_ERROR; return NGX_ERROR;
} }
ctx->rbtree = octx->rbtree; ctx->sh = octx->sh;
ctx->shpool = octx->shpool;
return NGX_OK; return NGX_OK;
} }
shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
if (shm_zone->shm.exists) { if (shm_zone->shm.exists) {
ctx->rbtree = shpool->data; ctx->sh = ctx->shpool->data;
return NGX_OK; return NGX_OK;
} }
ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); ctx->sh = ngx_slab_alloc(ctx->shpool,
if (ctx->rbtree == NULL) { sizeof(ngx_stream_limit_conn_shctx_t));
if (ctx->sh == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
shpool->data = ctx->rbtree; ctx->shpool->data = ctx->sh;
sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
if (sentinel == NULL) {
return NGX_ERROR;
}
ngx_rbtree_init(ctx->rbtree, sentinel,
ngx_stream_limit_conn_rbtree_insert_value); ngx_stream_limit_conn_rbtree_insert_value);
len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len; len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
shpool->log_ctx = ngx_slab_alloc(shpool, len); ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
if (shpool->log_ctx == NULL) { if (ctx->shpool->log_ctx == NULL) {
return NGX_ERROR; return NGX_ERROR;
} }
ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z", ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
&shm_zone->shm.name); &shm_zone->shm.name);
return NGX_OK; return NGX_OK;
} }
static ngx_int_t
ngx_stream_limit_conn_status_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data)
{
if (s->limit_conn_status == 0) {
v->not_found = 1;
return NGX_OK;
}
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->len = ngx_stream_limit_conn_status[s->limit_conn_status - 1].len;
v->data = ngx_stream_limit_conn_status[s->limit_conn_status - 1].data;
return NGX_OK;
}
static void * static void *
ngx_stream_limit_conn_create_conf(ngx_conf_t *cf) ngx_stream_limit_conn_create_conf(ngx_conf_t *cf)
{ {
@@ -444,6 +513,7 @@ ngx_stream_limit_conn_create_conf(ngx_conf_t *cf)
*/ */
conf->log_level = NGX_CONF_UNSET_UINT; conf->log_level = NGX_CONF_UNSET_UINT;
conf->dry_run = NGX_CONF_UNSET;
return conf; return conf;
} }
@@ -461,6 +531,8 @@ ngx_stream_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR);
ngx_conf_merge_value(conf->dry_run, prev->dry_run, 0);
return NGX_CONF_OK; return NGX_CONF_OK;
} }
@@ -627,6 +699,25 @@ ngx_stream_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
} }
static ngx_int_t
ngx_stream_limit_conn_add_variables(ngx_conf_t *cf)
{
ngx_stream_variable_t *var, *v;
for (v = ngx_stream_limit_conn_vars; v->name.len; v++) {
var = ngx_stream_add_variable(cf, &v->name, v->flags);
if (var == NULL) {
return NGX_ERROR;
}
var->get_handler = v->get_handler;
var->data = v->data;
}
return NGX_OK;
}
static ngx_int_t static ngx_int_t
ngx_stream_limit_conn_init(ngx_conf_t *cf) ngx_stream_limit_conn_init(ngx_conf_t *cf)
{ {
+2 -1
View File
@@ -839,7 +839,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
u->upstream_buf.last = p; u->upstream_buf.last = p;
} }
if (c->buffer && c->buffer->pos < c->buffer->last) { if (c->buffer && c->buffer->pos <= c->buffer->last) {
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
"stream proxy add preread buffer: %uz", "stream proxy add preread buffer: %uz",
c->buffer->last - c->buffer->pos); c->buffer->last - c->buffer->pos);
@@ -853,6 +853,7 @@ ngx_stream_proxy_init_upstream(ngx_stream_session_t *s)
*cl->buf = *c->buffer; *cl->buf = *c->buffer;
cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module; cl->buf->tag = (ngx_buf_tag_t) &ngx_stream_proxy_module;
cl->buf->temporary = (cl->buf->pos == cl->buf->last) ? 0 : 1;
cl->buf->flush = 1; cl->buf->flush = 1;
cl->next = u->upstream_out; cl->next = u->upstream_out;
+2 -1
View File
@@ -234,7 +234,8 @@ ngx_stream_write_filter(ngx_stream_session_t *s, ngx_chain_t *in,
if (size == 0 if (size == 0
&& !(c->buffered & NGX_LOWLEVEL_BUFFERED) && !(c->buffered & NGX_LOWLEVEL_BUFFERED)
&& !(last && c->need_last_buf)) && !(last && c->need_last_buf)
&& !(c->type == SOCK_DGRAM && flush))
{ {
if (last || flush || sync) { if (last || flush || sync) {
for (cl = *out; cl; /* void */) { for (cl = *out; cl; /* void */) {