Compare commits

..
117 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
Hakase f65d4faa78 Latest update - 7592 2019-11-07 22:28:33 +09:00
Hakase d12bc8b656 Latest update - 7591 2019-10-24 21:00:01 +09:00
Hakase 7451bdd624 Version bump - v1.17.6 2019-10-24 20:59:42 +09:00
Hakase 38c401869f Release - v1.17.5 2019-10-24 20:59:16 +09:00
Hakase 8be97f4f6c Latest update - 7586 2019-10-24 20:58:54 +09:00
Hakase 50320dd197 Submodule update. 2019-10-17 23:56:38 +09:00
Hakase a6a35de341 Latest update - 7584 2019-10-17 23:53:16 +09:00
Hakase deb38ff87c Latest update - 7580 2019-10-16 08:53:14 +09:00
Hakase 8b760dce84 Latest update - 7579 2019-10-09 22:16:35 +09:00
Hakase 97092a7563 Latest update - 7576 2019-10-05 18:15:43 +09:00
Hakase f6e254ee01 Submodule update. 2019-09-25 02:30:37 +09:00
Hakase f5c2a2fc32 Version bump - v1.17.5 2019-09-25 02:29:56 +09:00
Hakase 9c64adbaf0 Release - v1.17.4 2019-09-25 02:29:30 +09:00
Hakase f730927e80 Latest update - 7572 2019-09-25 02:28:42 +09:00
Hakase 51eeb183ba Submodule update. 2019-09-21 00:46:28 +09:00
Hakase 10d3e51b9a Latest update - 7569 2019-09-20 03:48:06 +09:00
Hakase a3411665e2 Latest update - 7567 2019-09-18 01:03:41 +09:00
Hakase c0b58bbcf6 Latest update - 7566 2019-09-16 13:39:01 +09:00
Hakase d808b37656 Latest update - 7563 2019-09-06 08:41:03 +09:00
Hakase 03397594eb Latest update - 7561 2019-08-20 23:48:53 +09:00
Hakase 4306e53ad8 Latest update - 7560 2019-08-19 20:42:36 +09:00
Hakase b68cbb3eb3 Version bump - v1.17.4 2019-08-14 16:00:58 +09:00
Hakase ce26759c9c Release - v1.17.3 2019-08-14 16:00:33 +09:00
Hakase 21524b58bf Latest update - 7549 2019-08-14 15:59:44 +09:00
Hakase f56ad45457 Submodule update. 2019-08-04 17:41:12 +09:00
Hakase cbaaa317da Latest update - 7546 2019-08-02 17:47:18 +09:00
Hakase ae67e2622d Version bump - v1.17.3 2019-07-29 17:48:03 +09:00
Hakase 47cdb7029d Release - v1.17.2 2019-07-29 17:47:46 +09:00
Hakase f3f38a56ad Latest update - 7541 2019-07-20 18:06:33 +09:00
Hakase 28f62b6672 Latest update - 7540 2019-07-19 08:47:57 +09:00
Hakase a17d307d9b Submodule update. 2019-07-13 19:16:05 +09:00
Hakase 0cc7a3aba8 Latest update - 7534 2019-07-13 19:14:22 +09:00
Hakase bd600385ec Latest update - 7522 2019-07-11 00:56:38 +09:00
Hakase 04b26acf63 Version bump - 1.17.2 2019-06-26 00:45:13 +09:00
Hakase 822cd094bd Release 1.17.1 2019-06-26 00:44:54 +09:00
Hakase d15a32b24b Latest update - 7517 2019-06-26 00:44:34 +09:00
Hakase d853e3765b Latest update - 7516 2019-06-19 01:03:38 +09:00
Hakase b8b58c0e47 Latest update - 7515 2019-06-07 00:36:43 +09:00
Hakase 3e1e852389 Latest update - 7514 2019-06-04 19:54:29 +09:00
Hakase 3f31c9270d Latest update - 7513 2019-05-28 09:37:27 +09:00
Hakase 75dc02a1ae Version bump. - v1.17.1 2019-05-23 12:05:00 +09:00
Hakase c45b1861fb Submodule update. 2019-05-23 12:04:34 +09:00
Hakase a89def5d34 v1.17.0 2019-05-23 11:59:23 +09:00
Hakase b820457c51 Latest update - 7509 2019-05-17 02:54:19 +09:00
Hakase 83915a055e Latest update - 7508 2019-05-14 08:44:24 +09:00
Hakase b0003469d0 Submodule update. 2019-05-06 22:40:28 +09:00
Hakase 8941c16aa8 Change my domain. (hakase.io -> haka.se) 2019-05-02 20:57:25 +09:00
Hakase b5f41941cd Submodule update. 2019-04-26 08:42:28 +09:00
Hakase dd71767aff Latest update - 7505 2019-04-25 08:30:35 +09:00
Hakase 7564cabbbe Latest update - 7502 2019-04-24 22:21:21 +09:00
Hakase b714ce2c1c Version bump - v1.17.0 2019-04-24 22:20:48 +09:00
127 changed files with 5555 additions and 1373 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
+14
View File
@@ -438,3 +438,17 @@ d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9
75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10 75f5c7f628411c79c7044102049f7ab4f7a246e7 release-1.15.10
5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11 5155d0296a5ef9841f035920527ffdb771076b44 release-1.15.11
0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12
054c1c46395caff79bb4caf16f40b331f71bb6dd release-1.17.0
7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1
2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2
ed4303aa1b31a9aad5440640c0840d9d0af45fed release-1.17.3
ce2ced3856909f36f8130c99eaa4dbdbae636ddc release-1.17.4
9af0dddbddb2c368bfedd2801bc100ffad01e19b release-1.17.5
de68d0d94320cbf033599c6f3ca37e5335c67fd7 release-1.17.6
e56295fe0ea76bf53b06bffa77a2d3a9a335cb8c release-1.17.7
fdacd273711ddf20f778c1fb91529ab53979a454 release-1.17.8
5e8d52bca714d4b85284ddb649d1ba4a3ca978a8 release-1.17.9
c44970de01474f6f3e01b0adea85ec1d03e3a5f2 release-1.17.10
cbe6ba650211541310618849168631ce0b788f35 release-1.19.0
062920e2f3bf871ef7a3d8496edec1b3065faf80 release-1.19.1
a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2
+5 -3
View File
@@ -1,7 +1,9 @@
# Hakase-nginx # Hakase-nginx
**My nginx build files.** **My nginx build files.**
Example Web Server - [https://ssl.hakase.io/](https://ssl.hakase.io/) ## This repository is no longer operational. Use an alternative such as tengine.
Example Web Server - [https://ssl.haka.se/](https://ssl.haka.se/)
## Please install dependency library. ## Please install dependency library.
- CentOS / Red Hat - `yum install jemalloc-devel libuuid-devel libatomic libatomic_ops-devel expat-devel unzip autoconf automake libtool gd-devel libmaxminddb-devel libxslt-devel libxml2-devel gcc-c++ curl` - CentOS / Red Hat - `yum install jemalloc-devel libuuid-devel libatomic libatomic_ops-devel expat-devel unzip autoconf automake libtool gd-devel libmaxminddb-devel libxslt-devel libxml2-devel gcc-c++ curl`
@@ -33,8 +35,8 @@ Example Web Server - [https://ssl.hakase.io/](https://ssl.hakase.io/)
- 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} \
+2 -17
View File
@@ -102,21 +102,6 @@ if [ $HTTP = YES ]; then
fi fi
if [ $HTTP_SSI = YES ]; then
HTTP_POSTPONE=YES
fi
if [ $HTTP_SLICE = YES ]; then
HTTP_POSTPONE=YES
fi
if [ $HTTP_ADDITION = YES ]; then
HTTP_POSTPONE=YES
fi
# the module order is important # the module order is important
# ngx_http_static_module # ngx_http_static_module
# ngx_http_gzip_static_module # ngx_http_gzip_static_module
@@ -252,13 +237,13 @@ if [ $HTTP = YES ]; then
. auto/module . auto/module
fi fi
if [ $HTTP_POSTPONE = YES ]; then if :; then
ngx_module_name=ngx_http_postpone_filter_module ngx_module_name=ngx_http_postpone_filter_module
ngx_module_incs= ngx_module_incs=
ngx_module_deps= ngx_module_deps=
ngx_module_srcs=src/http/ngx_http_postpone_filter_module.c ngx_module_srcs=src/http/ngx_http_postpone_filter_module.c
ngx_module_libs= ngx_module_libs=
ngx_module_link=$HTTP_POSTPONE ngx_module_link=YES
. auto/module . auto/module
fi fi
-1
View File
@@ -61,7 +61,6 @@ HTTP_SSL=NO
HTTP_V2=NO HTTP_V2=NO
HTTP_V2_HPACK_ENC=NO HTTP_V2_HPACK_ENC=NO
HTTP_SSI=YES HTTP_SSI=YES
HTTP_POSTPONE=NO
HTTP_REALIP=NO HTTP_REALIP=NO
HTTP_XSLT=NO HTTP_XSLT=NO
HTTP_IMAGE_FILTER=NO HTTP_IMAGE_FILTER=NO
+12
View File
@@ -943,6 +943,18 @@ ngx_feature_test="int i = FIONBIO; printf(\"%d\", i)"
. auto/feature . auto/feature
ngx_feature="ioctl(FIONREAD)"
ngx_feature_name="NGX_HAVE_FIONREAD"
ngx_feature_run=no
ngx_feature_incs="#include <sys/ioctl.h>
#include <stdio.h>
$NGX_INCLUDE_SYS_FILIO_H"
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="int i = FIONREAD; printf(\"%d\", i)"
. auto/feature
ngx_feature="struct tm.tm_gmtoff" ngx_feature="struct tm.tm_gmtoff"
ngx_feature_name="NGX_HAVE_GMTOFF" ngx_feature_name="NGX_HAVE_GMTOFF"
ngx_feature_run=no ngx_feature_run=no
+6 -1
View File
@@ -31,7 +31,7 @@ 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;
@@ -44,11 +44,16 @@ http {
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 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
# IPv6
#set_real_ip_from 2400:cb00::/32; #set_real_ip_from 2400:cb00::/32;
#set_real_ip_from 2606:4700::/32; #set_real_ip_from 2606:4700::/32;
#set_real_ip_from 2803:f800::/32; #set_real_ip_from 2803:f800::/32;
#set_real_ip_from 2405:b500::/32; #set_real_ip_from 2405:b500::/32;
#set_real_ip_from 2405:8100::/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 ###
+83 -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,7 +333,9 @@ 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_preread syn keyword ngxDirective contained js_preread
syn keyword ngxDirective contained js_set syn keyword ngxDirective contained js_set
syn keyword ngxDirective contained keepalive syn keyword ngxDirective contained keepalive
@@ -347,12 +350,14 @@ 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
syn keyword ngxDirective contained limit_rate syn keyword ngxDirective contained limit_rate
syn keyword ngxDirective contained limit_rate_after syn keyword ngxDirective contained limit_rate_after
syn keyword ngxDirective contained limit_req syn keyword ngxDirective contained limit_req
syn keyword ngxDirective contained limit_req_dry_run
syn keyword ngxDirective contained limit_req_log_level syn keyword ngxDirective contained limit_req_log_level
syn keyword ngxDirective contained limit_req_status syn keyword ngxDirective contained limit_req_status
syn keyword ngxDirective contained limit_req_zone syn keyword ngxDirective contained limit_req_zone
@@ -472,6 +477,7 @@ syn keyword ngxDirective contained proxy_requests
syn keyword ngxDirective contained proxy_responses syn keyword ngxDirective contained proxy_responses
syn keyword ngxDirective contained proxy_send_lowat syn keyword ngxDirective contained proxy_send_lowat
syn keyword ngxDirective contained proxy_send_timeout syn keyword ngxDirective contained proxy_send_timeout
syn keyword ngxDirective contained proxy_session_drop
syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_body
syn keyword ngxDirective contained proxy_set_header syn keyword ngxDirective contained proxy_set_header
syn keyword ngxDirective contained proxy_socket_keepalive syn keyword ngxDirective contained proxy_socket_keepalive
@@ -592,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
@@ -767,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
@@ -788,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
@@ -815,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
@@ -851,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
@@ -868,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
@@ -876,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
@@ -939,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
@@ -988,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
@@ -997,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
@@ -1044,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
@@ -1325,6 +1346,7 @@ syn keyword ngxDirectiveThirdParty contained lua_check_client_abort
syn keyword ngxDirectiveThirdParty contained lua_code_cache syn keyword ngxDirectiveThirdParty contained lua_code_cache
syn keyword ngxDirectiveThirdParty contained lua_fake_shm syn keyword ngxDirectiveThirdParty contained lua_fake_shm
syn keyword ngxDirectiveThirdParty contained lua_http10_buffering syn keyword ngxDirectiveThirdParty contained lua_http10_buffering
syn keyword ngxDirectiveThirdParty contained lua_load_resty_core
syn keyword ngxDirectiveThirdParty contained lua_malloc_trim syn keyword ngxDirectiveThirdParty contained lua_malloc_trim
syn keyword ngxDirectiveThirdParty contained lua_max_pending_timers syn keyword ngxDirectiveThirdParty contained lua_max_pending_timers
syn keyword ngxDirectiveThirdParty contained lua_max_running_timers syn keyword ngxDirectiveThirdParty contained lua_max_running_timers
@@ -1779,6 +1801,7 @@ syn keyword ngxDirectiveThirdParty contained vod_expires_live_time_dependent
syn keyword ngxDirectiveThirdParty contained vod_fallback_upstream_location syn keyword ngxDirectiveThirdParty contained vod_fallback_upstream_location
syn keyword ngxDirectiveThirdParty contained vod_force_continuous_timestamps syn keyword ngxDirectiveThirdParty contained vod_force_continuous_timestamps
syn keyword ngxDirectiveThirdParty contained vod_force_playlist_type_vod syn keyword ngxDirectiveThirdParty contained vod_force_playlist_type_vod
syn keyword ngxDirectiveThirdParty contained vod_force_sequence_index
syn keyword ngxDirectiveThirdParty contained vod_gop_look_ahead syn keyword ngxDirectiveThirdParty contained vod_gop_look_ahead
syn keyword ngxDirectiveThirdParty contained vod_gop_look_behind syn keyword ngxDirectiveThirdParty contained vod_gop_look_behind
syn keyword ngxDirectiveThirdParty contained vod_ignore_edit_list syn keyword ngxDirectiveThirdParty contained vod_ignore_edit_list
@@ -1982,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
@@ -2303,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
+912
View File
@@ -5,6 +5,918 @@
<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">
<change type="feature">
<para lang="ru">
теперь nginx использует вызов ioctl(FIONREAD), если он доступен,
чтобы избежать чтения из быстрого соединения в течение долгого времени.
</para>
<para lang="en">
now nginx uses ioctl(FIONREAD), if available,
to avoid reading from a fast connection for a long time.
</para>
</change>
<change type="bugfix">
<para lang="ru">
неполные закодированные символы в конце URI запроса игнорировались.
</para>
<para lang="en">
incomplete escaped characters at the end of the request URI were ignored.
</para>
</change>
<change type="bugfix">
<para lang="ru">
"/." и "/.." в конце URI запроса не нормализовывались.
</para>
<para lang="en">
"/." and "/.." at the end of the request URI were not normalized.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в директиве merge_slashes.
</para>
<para lang="en">
in the "merge_slashes" directive.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в директиве ignore_invalid_headers.<br/>
Спасибо Alan Kemp.
</para>
<para lang="en">
in the "ignore_invalid_headers" directive.<br/>
Thanks to Alan Kemp.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx не собирался с MinGW-w64 gcc 8.1 и новее.
</para>
<para lang="en">
nginx could not be built with MinGW-w64 gcc 8.1 or newer.
</para>
</change>
</changes>
<changes ver="1.17.4" date="2019-09-24">
<change type="change">
<para lang="ru">
улучшено детектирование некорректного поведения клиентов в HTTP/2.
</para>
<para lang="en">
better detection of incorrect client behavior in HTTP/2.
</para>
</change>
<change type="change">
<para lang="ru">
в обработке непрочитанного тела запроса
при возврате ошибок в HTTP/2.
</para>
<para lang="en">
in handling of not fully read client request body
when returning errors in HTTP/2.
</para>
</change>
<change type="bugfix">
<para lang="ru">
директива worker_shutdown_timeout могла не работать
при использовании HTTP/2.
</para>
<para lang="en">
the "worker_shutdown_timeout" directive might not work
when using HTTP/2.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании HTTP/2 и директивы proxy_request_buffering
в рабочем процессе мог произойти segmentation fault.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
when using HTTP/2 and the "proxy_request_buffering" directive.
</para>
</change>
<change type="bugfix">
<para lang="ru">
на Windows при использовании SSL
уровень записи в лог ошибки ECONNABORTED был "crit" вместо "error".
</para>
<para lang="en">
the ECONNABORTED error log level was "crit" instead of "error"
on Windows when using SSL.
</para>
</change>
<change type="bugfix">
<para lang="ru">
nginx игнорировал лишние данные при использовании chunked transfer encoding.
</para>
<para lang="en">
nginx ignored extra data when using chunked transfer encoding.
</para>
</change>
<change type="bugfix">
<para lang="ru">
если использовалась директива return и
при чтении тела запроса возникала ошибка,
nginx всегда возвращал ошибку 500.
</para>
<para lang="en">
nginx always returned the 500 error
if the "return" directive was used
and an error occurred during reading client request body.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в обработке ошибок выделения памяти.
</para>
<para lang="en">
in memory allocation error handling.
</para>
</change>
</changes>
<changes ver="1.17.3" date="2019-08-13">
<change type="security">
<para lang="ru">
при использовании HTTP/2 клиент мог вызвать
чрезмерное потребление памяти и ресурсов процессора
(CVE-2019-9511, CVE-2019-9513, CVE-2019-9516).
</para>
<para lang="en">
when using HTTP/2 a client might cause
excessive memory consumption and CPU usage
(CVE-2019-9511, CVE-2019-9513, CVE-2019-9516).
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании сжатия в логах могли появляться сообщения "zero size buf";
ошибка появилась в 1.17.2.
</para>
<para lang="en">
"zero size buf" alerts might appear in logs when using gzipping;
the bug had appeared in 1.17.2.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании директивы resolver в SMTP прокси-сервере
в рабочем процессе мог произойти segmentation fault.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if the "resolver" directive was used in SMTP proxy.
</para>
</change>
</changes>
<changes ver="1.17.2" date="2019-07-23">
<change type="change">
<para lang="ru">
минимальная поддерживаемая версия zlib&mdash;1.2.0.4.<br/>
Спасибо Илье Леошкевичу.
</para>
<para lang="en">
minimum supported zlib version is 1.2.0.4.<br/>
Thanks to Ilya Leoshkevich.
</para>
</change>
<change type="change">
<para lang="ru">
метод $r->internal_redirect() встроенного перла
теперь ожидает закодированный URI.
</para>
<para lang="en">
the $r->internal_redirect() embedded perl method
now expects escaped URIs.
</para>
</change>
<change type="feature">
<para lang="ru">
теперь с помощью метода $r->internal_redirect() встроенного перла
можно перейти в именованный location.
</para>
<para lang="en">
it is now possible to switch to a named location
using the $r->internal_redirect() embedded perl method.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в обработке ошибок во встроенном перле.
</para>
<para lang="en">
in error handling in embedded perl.
</para>
</change>
<change type="bugfix">
<para lang="ru">
на старте или во время переконфигурации мог произойти segmentation fault,
если в конфигурации использовалось значение hash bucket size больше 64 килобайт.
</para>
<para lang="en">
a segmentation fault might occur on start or during reconfiguration
if hash bucket size larger than 64 kilobytes was used in the configuration.
</para>
</change>
<change type="bugfix">
<para lang="ru">
при использовании методов обработки соединений select, poll и /dev/poll
nginx мог нагружать процессор во время небуферизованного проксирования
и при проксировании WebSocket-соединений.
</para>
<para lang="en">
nginx might hog CPU during unbuffered proxying
and when proxying WebSocket connections
if the select, poll, or /dev/poll methods were used.
</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>
<change type="bugfix">
<para lang="ru">
в модуле ngx_http_ssi_filter_module.
</para>
<para lang="en">
in the ngx_http_ssi_filter_module.
</para>
</change>
</changes>
<changes ver="1.17.1" date="2019-06-25">
<change type="feature">
<para lang="ru">
директива limit_req_dry_run.
</para>
<para lang="en">
the "limit_req_dry_run" directive.
</para>
</change>
<change type="feature">
<para lang="ru">
при использовании директивы hash в блоке upstream
пустой ключ хэширования теперь приводит к переключению
на round-robin балансировку.<br/>
Спасибо Niklas Keller.
</para>
<para lang="en">
when using the "hash" directive inside the "upstream" block
an empty hash key now triggers round-robin balancing.<br/>
Thanks to Niklas Keller.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в рабочем процессе мог произойти segmentation fault,
если использовалось кэширование и директива image_filter,
а ошибки с кодом 415 перенаправлялись с помощью директивы error_page;
ошибка появилась в 1.11.10.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if caching was used along with the "image_filter" directive,
and errors with code 415 were redirected with the "error_page" directive;
the bug had appeared in 1.11.10.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в рабочем процессе мог произойти segmentation fault,
если использовался встроенный перл;
ошибка появилась в 1.7.3.
</para>
<para lang="en">
a segmentation fault might occur in a worker process
if embedded perl was used;
the bug had appeared in 1.7.3.
</para>
</change>
</changes>
<changes ver="1.17.0" date="2019-05-21">
<change type="feature">
<para lang="ru">
директивы limit_rate и limit_rate_after поддерживают переменные.
</para>
<para lang="en">
variables support in the "limit_rate" and "limit_rate_after" directives.
</para>
</change>
<change type="feature">
<para lang="ru">
директивы proxy_upload_rate и proxy_download_rate в модуле stream
поддерживают переменные.
</para>
<para lang="en">
variables support
in the "proxy_upload_rate" and "proxy_download_rate" directives
in the stream module.
</para>
</change>
<change type="change">
<para lang="ru">
минимальная поддерживаемая версия OpenSSL&mdash;0.9.8.
</para>
<para lang="en">
minimum supported OpenSSL version is 0.9.8.
</para>
</change>
<change type="change">
<para lang="ru">
теперь postpone-фильтр собирается всегда.
</para>
<para lang="en">
now the postpone filter is always built.
</para>
</change>
<change type="bugfix">
<para lang="ru">
директива include не работала в блоках if и limit_except.
</para>
<para lang="en">
the "include" directive did not work inside the "if" and "limit_except" blocks.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в обработке byte ranges.
</para>
<para lang="en">
in byte ranges processing.
</para>
</change>
</changes>
<changes ver="1.15.12" date="2019-04-16"> <changes ver="1.15.12" date="2019-04-16">
<change type="bugfix"> <change type="bugfix">
+2 -2
View File
@@ -6,9 +6,9 @@ TEMP = tmp
CC = cl CC = cl
OBJS = objs.msvc8 OBJS = objs.msvc8
OPENSSL = openssl-1.1.1b 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 1015013 #define nginx_version 1019003
#define NGINX_VERSION "1.15.13" #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)
+1 -1
View File
@@ -49,7 +49,7 @@
#define NGX_DIRECT_CONF 0x00010000 #define NGX_DIRECT_CONF 0x00010000
#define NGX_MAIN_CONF 0x01000000 #define NGX_MAIN_CONF 0x01000000
#define NGX_ANY_CONF 0x1F000000 #define NGX_ANY_CONF 0xFF000000
+18 -5
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;
if (c == NULL) {
ngx_drain_connections((ngx_cycle_t *) ngx_cycle); ngx_drain_connections((ngx_cycle_t *) ngx_cycle);
c = ngx_cycle->free_connections; 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++) {
+1 -2
View File
@@ -147,8 +147,7 @@ struct ngx_connection_s {
socklen_t socklen; socklen_t socklen;
ngx_str_t addr_text; ngx_str_t addr_text;
ngx_str_t proxy_protocol_addr; ngx_proxy_protocol_t *proxy_protocol;
in_port_t proxy_protocol_port;
#if (NGX_SSL || NGX_COMPAT) #if (NGX_SSL || NGX_COMPAT)
ngx_ssl_connection_t *ssl; ngx_ssl_connection_t *ssl;
+1
View File
@@ -26,6 +26,7 @@ typedef struct ngx_event_aio_s ngx_event_aio_t;
typedef struct ngx_connection_s ngx_connection_t; typedef struct ngx_connection_s ngx_connection_t;
typedef struct ngx_thread_task_s ngx_thread_task_t; typedef struct ngx_thread_task_s ngx_thread_task_t;
typedef struct ngx_ssl_s ngx_ssl_t; typedef struct ngx_ssl_s ngx_ssl_t;
typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
typedef struct ngx_ssl_connection_s ngx_ssl_connection_t; typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;
typedef struct ngx_udp_connection_s ngx_udp_connection_t; typedef struct ngx_udp_connection_s ngx_udp_connection_t;
+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;
+26 -5
View File
@@ -265,6 +265,14 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
return NGX_ERROR; return NGX_ERROR;
} }
if (hinit->bucket_size > 65536 - ngx_cacheline_size) {
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
"could not build %s, too large "
"%s_bucket_size: %i",
hinit->name, hinit->name, hinit->bucket_size);
return NGX_ERROR;
}
for (n = 0; n < nelts; n++) { for (n = 0; n < nelts; n++) {
if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
{ {
@@ -300,17 +308,19 @@ ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
} }
key = names[n].key_hash % size; key = names[n].key_hash % size;
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); len = test[key] + NGX_HASH_ELT_SIZE(&names[n]);
#if 0 #if 0
ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
"%ui: %ui %ui \"%V\"", "%ui: %ui %uz \"%V\"",
size, key, test[key], &names[n].key); size, key, len, &names[n].key);
#endif #endif
if (test[key] > (u_short) bucket_size) { if (len > bucket_size) {
goto next; goto next;
} }
test[key] = (u_short) len;
} }
goto found; goto found;
@@ -341,7 +351,18 @@ found:
} }
key = names[n].key_hash % size; key = names[n].key_hash % size;
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); len = test[key] + NGX_HASH_ELT_SIZE(&names[n]);
if (len > 65536 - ngx_cacheline_size) {
ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
"could not build %s, you should "
"increase %s_max_size: %i",
hinit->name, hinit->name, hinit->max_size);
ngx_free(test);
return NGX_ERROR;
}
test[key] = (u_short) len;
} }
len = 0; len = 0;
+151 -72
View File
@@ -40,6 +40,10 @@ typedef struct {
} ngx_proxy_protocol_inet6_addrs_t; } ngx_proxy_protocol_inet6_addrs_t;
static u_char *ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p,
u_char *last, ngx_str_t *addr);
static u_char *ngx_proxy_protocol_read_port(u_char *p, u_char *last,
in_port_t *port, u_char sep);
static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, static u_char *ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf,
u_char *last); u_char *last);
@@ -48,8 +52,8 @@ u_char *
ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last) ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
{ {
size_t len; size_t len;
u_char ch, *p, *addr, *port; u_char *p;
ngx_int_t n; ngx_proxy_protocol_t *pp;
static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n"; static const u_char signature[] = "\r\n\r\n\0\r\nQUIT\n";
@@ -83,73 +87,47 @@ ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *last)
} }
p += 5; p += 5;
addr = p;
for ( ;; ) { pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
if (p == last) { if (pp == NULL) {
goto invalid;
}
ch = *p++;
if (ch == ' ') {
break;
}
if (ch != ':' && ch != '.'
&& (ch < 'a' || ch > 'f')
&& (ch < 'A' || ch > 'F')
&& (ch < '0' || ch > '9'))
{
goto invalid;
}
}
len = p - addr - 1;
c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, len);
if (c->proxy_protocol_addr.data == NULL) {
return NULL; return NULL;
} }
ngx_memcpy(c->proxy_protocol_addr.data, addr, len); p = ngx_proxy_protocol_read_addr(c, p, last, &pp->src_addr);
c->proxy_protocol_addr.len = len; if (p == NULL) {
goto invalid;
}
p = ngx_proxy_protocol_read_addr(c, p, last, &pp->dst_addr);
if (p == NULL) {
goto invalid;
}
p = ngx_proxy_protocol_read_port(p, last, &pp->src_port, ' ');
if (p == NULL) {
goto invalid;
}
p = ngx_proxy_protocol_read_port(p, last, &pp->dst_port, CR);
if (p == NULL) {
goto invalid;
}
for ( ;; ) {
if (p == last) { if (p == last) {
goto invalid; goto invalid;
} }
if (*p++ == ' ') { if (*p++ != LF) {
break;
}
}
port = p;
for ( ;; ) {
if (p == last) {
goto invalid; goto invalid;
} }
if (*p++ == ' ') { ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
break; "PROXY protocol src: %V %d, dst: %V %d",
} &pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
}
len = p - port - 1; c->proxy_protocol = pp;
n = ngx_atoi(port, len); return p;
if (n < 0 || n > 65535) {
goto invalid;
}
c->proxy_protocol_port = (in_port_t) n;
ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0,
"PROXY protocol address: %V %d", &c->proxy_protocol_addr,
c->proxy_protocol_port);
skip: skip:
@@ -168,6 +146,82 @@ invalid:
} }
static u_char *
ngx_proxy_protocol_read_addr(ngx_connection_t *c, u_char *p, u_char *last,
ngx_str_t *addr)
{
size_t len;
u_char ch, *pos;
pos = p;
for ( ;; ) {
if (p == last) {
return NULL;
}
ch = *p++;
if (ch == ' ') {
break;
}
if (ch != ':' && ch != '.'
&& (ch < 'a' || ch > 'f')
&& (ch < 'A' || ch > 'F')
&& (ch < '0' || ch > '9'))
{
return NULL;
}
}
len = p - pos - 1;
addr->data = ngx_pnalloc(c->pool, len);
if (addr->data == NULL) {
return NULL;
}
ngx_memcpy(addr->data, pos, len);
addr->len = len;
return p;
}
static u_char *
ngx_proxy_protocol_read_port(u_char *p, u_char *last, in_port_t *port,
u_char sep)
{
size_t len;
u_char *pos;
ngx_int_t n;
pos = p;
for ( ;; ) {
if (p == last) {
return NULL;
}
if (*p++ == sep) {
break;
}
}
len = p - pos - 1;
n = ngx_atoi(pos, len);
if (n < 0 || n > 65535) {
return NULL;
}
*port = (in_port_t) n;
return p;
}
u_char * u_char *
ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last) ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *last)
{ {
@@ -219,7 +273,8 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
size_t len; size_t len;
socklen_t socklen; socklen_t socklen;
ngx_uint_t version, command, family, transport; ngx_uint_t version, command, family, transport;
ngx_sockaddr_t sockaddr; ngx_sockaddr_t src_sockaddr, dst_sockaddr;
ngx_proxy_protocol_t *pp;
ngx_proxy_protocol_header_t *header; ngx_proxy_protocol_header_t *header;
ngx_proxy_protocol_inet_addrs_t *in; ngx_proxy_protocol_inet_addrs_t *in;
#if (NGX_HAVE_INET6) #if (NGX_HAVE_INET6)
@@ -266,6 +321,11 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
return end; return end;
} }
pp = ngx_pcalloc(c->pool, sizeof(ngx_proxy_protocol_t));
if (pp == NULL) {
return NULL;
}
family = header->family_transport >> 4; family = header->family_transport >> 4;
switch (family) { switch (family) {
@@ -278,11 +338,16 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
in = (ngx_proxy_protocol_inet_addrs_t *) buf; in = (ngx_proxy_protocol_inet_addrs_t *) buf;
sockaddr.sockaddr_in.sin_family = AF_INET; src_sockaddr.sockaddr_in.sin_family = AF_INET;
sockaddr.sockaddr_in.sin_port = 0; src_sockaddr.sockaddr_in.sin_port = 0;
memcpy(&sockaddr.sockaddr_in.sin_addr, in->src_addr, 4); memcpy(&src_sockaddr.sockaddr_in.sin_addr, in->src_addr, 4);
c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in->src_port); dst_sockaddr.sockaddr_in.sin_family = AF_INET;
dst_sockaddr.sockaddr_in.sin_port = 0;
memcpy(&dst_sockaddr.sockaddr_in.sin_addr, in->dst_addr, 4);
pp->src_port = ngx_proxy_protocol_parse_uint16(in->src_port);
pp->dst_port = ngx_proxy_protocol_parse_uint16(in->dst_port);
socklen = sizeof(struct sockaddr_in); socklen = sizeof(struct sockaddr_in);
@@ -300,11 +365,16 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf; in6 = (ngx_proxy_protocol_inet6_addrs_t *) buf;
sockaddr.sockaddr_in6.sin6_family = AF_INET6; src_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
sockaddr.sockaddr_in6.sin6_port = 0; src_sockaddr.sockaddr_in6.sin6_port = 0;
memcpy(&sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16); memcpy(&src_sockaddr.sockaddr_in6.sin6_addr, in6->src_addr, 16);
c->proxy_protocol_port = ngx_proxy_protocol_parse_uint16(in6->src_port); dst_sockaddr.sockaddr_in6.sin6_family = AF_INET6;
dst_sockaddr.sockaddr_in6.sin6_port = 0;
memcpy(&dst_sockaddr.sockaddr_in6.sin6_addr, in6->dst_addr, 16);
pp->src_port = ngx_proxy_protocol_parse_uint16(in6->src_port);
pp->dst_port = ngx_proxy_protocol_parse_uint16(in6->dst_port);
socklen = sizeof(struct sockaddr_in6); socklen = sizeof(struct sockaddr_in6);
@@ -321,23 +391,32 @@ ngx_proxy_protocol_v2_read(ngx_connection_t *c, u_char *buf, u_char *last)
return end; return end;
} }
c->proxy_protocol_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN); pp->src_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
if (c->proxy_protocol_addr.data == NULL) { if (pp->src_addr.data == NULL) {
return NULL; return NULL;
} }
c->proxy_protocol_addr.len = ngx_sock_ntop(&sockaddr.sockaddr, socklen, pp->src_addr.len = ngx_sock_ntop(&src_sockaddr.sockaddr, socklen,
c->proxy_protocol_addr.data, pp->src_addr.data, NGX_SOCKADDR_STRLEN, 0);
NGX_SOCKADDR_STRLEN, 0);
ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, pp->dst_addr.data = ngx_pnalloc(c->pool, NGX_SOCKADDR_STRLEN);
"PROXY protocol v2 address: %V %d", &c->proxy_protocol_addr, if (pp->dst_addr.data == NULL) {
c->proxy_protocol_port); return NULL;
}
pp->dst_addr.len = ngx_sock_ntop(&dst_sockaddr.sockaddr, socklen,
pp->dst_addr.data, NGX_SOCKADDR_STRLEN, 0);
ngx_log_debug4(NGX_LOG_DEBUG_CORE, c->log, 0,
"PROXY protocol v2 src: %V %d, dst: %V %d",
&pp->src_addr, pp->src_port, &pp->dst_addr, pp->dst_port);
if (buf < end) { if (buf < end) {
ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0,
"PROXY protocol v2 %z bytes of tlv ignored", end - buf); "PROXY protocol v2 %z bytes of tlv ignored", end - buf);
} }
c->proxy_protocol = pp;
return end; return end;
} }
+8
View File
@@ -16,6 +16,14 @@
#define NGX_PROXY_PROTOCOL_MAX_HEADER 107 #define NGX_PROXY_PROTOCOL_MAX_HEADER 107
struct ngx_proxy_protocol_s {
ngx_str_t src_addr;
ngx_str_t dst_addr;
in_port_t src_port;
in_port_t dst_port;
};
u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf, u_char *ngx_proxy_protocol_read(ngx_connection_t *c, u_char *buf,
u_char *last); u_char *last);
u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf, u_char *ngx_proxy_protocol_write(ngx_connection_t *c, u_char *buf,
-5
View File
@@ -174,13 +174,8 @@ ngx_rbtree_delete(ngx_rbtree_t *tree, ngx_rbtree_node_t *node)
} else { } else {
subst = ngx_rbtree_min(node->right, sentinel); subst = ngx_rbtree_min(node->right, sentinel);
if (subst->left != sentinel) {
temp = subst->left;
} else {
temp = subst->right; temp = subst->right;
} }
}
if (subst == *root) { if (subst == *root) {
*root = temp; *root = temp;
+2 -1
View File
@@ -972,7 +972,8 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
name = ngx_resolver_dup(r, rn->name, rn->nlen); name = ngx_resolver_dup(r, rn->name, rn->nlen);
if (name == NULL) { if (name == NULL) {
goto failed; ngx_resolver_free(r, ctx);
return NGX_ERROR;
} }
ctx->name.len = rn->nlen; ctx->name.len = rn->nlen;
+1
View File
@@ -495,6 +495,7 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
if ((revents & POLLIN) && rev->active) { if ((revents & POLLIN) && rev->active) {
rev->ready = 1; rev->ready = 1;
rev->available = -1;
if (flags & NGX_POST_EVENTS) { if (flags & NGX_POST_EVENTS) {
queue = rev->accept ? &ngx_posted_accept_events queue = rev->accept ? &ngx_posted_accept_events
+1 -2
View File
@@ -886,11 +886,10 @@ ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
if (revents & EPOLLRDHUP) { if (revents & EPOLLRDHUP) {
rev->pending_eof = 1; rev->pending_eof = 1;
} }
rev->available = 1;
#endif #endif
rev->ready = 1; rev->ready = 1;
rev->available = -1;
if (flags & NGX_POST_EVENTS) { if (flags & NGX_POST_EVENTS) {
queue = rev->accept ? &ngx_posted_accept_events queue = rev->accept ? &ngx_posted_accept_events
+1
View File
@@ -559,6 +559,7 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
if (revents & POLLIN) { if (revents & POLLIN) {
rev->ready = 1; rev->ready = 1;
rev->available = -1;
if (flags & NGX_POST_EVENTS) { if (flags & NGX_POST_EVENTS) {
queue = rev->accept ? &ngx_posted_accept_events queue = rev->accept ? &ngx_posted_accept_events
+1
View File
@@ -370,6 +370,7 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
ev = c->read; ev = c->read;
ev->ready = 1; ev->ready = 1;
ev->available = -1;
queue = ev->accept ? &ngx_posted_accept_events queue = ev->accept ? &ngx_posted_accept_events
: &ngx_posted_events; : &ngx_posted_events;
+1
View File
@@ -330,6 +330,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
if (found) { if (found) {
ev->ready = 1; ev->ready = 1;
ev->available = -1;
queue = ev->accept ? &ngx_posted_accept_events queue = ev->accept ? &ngx_posted_accept_events
: &ngx_posted_events; : &ngx_posted_events;
@@ -380,6 +380,7 @@ ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
ev = c->read; ev = c->read;
ev->ready = 1; ev->ready = 1;
ev->available = -1;
queue = ev->accept ? &ngx_posted_accept_events queue = ev->accept ? &ngx_posted_accept_events
: &ngx_posted_events; : &ngx_posted_events;
@@ -330,6 +330,7 @@ ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
if (found) { if (found) {
ev->ready = 1; ev->ready = 1;
ev->available = -1;
queue = ev->accept ? &ngx_posted_accept_events queue = ev->accept ? &ngx_posted_accept_events
: &ngx_posted_events; : &ngx_posted_events;
+6
View File
@@ -237,6 +237,11 @@ ngx_process_events_and_timers(ngx_cycle_t *cycle)
} }
} }
if (!ngx_queue_empty(&ngx_posted_next_events)) {
ngx_event_move_posted_next(cycle);
timer = 0;
}
delta = ngx_current_msec; delta = ngx_current_msec;
(void) ngx_process_events(cycle, timer, flags); (void) ngx_process_events(cycle, timer, flags);
@@ -639,6 +644,7 @@ ngx_event_process_init(ngx_cycle_t *cycle)
#endif #endif
ngx_queue_init(&ngx_posted_accept_events); ngx_queue_init(&ngx_posted_accept_events);
ngx_queue_init(&ngx_posted_next_events);
ngx_queue_init(&ngx_posted_events); ngx_queue_init(&ngx_posted_events);
if (ngx_event_timer_init(cycle->log) == NGX_ERROR) { if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {
+1 -8
View File
@@ -91,21 +91,14 @@ struct ngx_event_s {
* write: available space in buffer when event is ready * write: available space in buffer when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag * or lowat when event is set with NGX_LOWAT_EVENT flag
* *
* epoll with EPOLLRDHUP:
* accept: 1 if accept many, 0 otherwise
* read: 1 if there can be data to read, 0 otherwise
*
* iocp: TODO * iocp: TODO
* *
* otherwise: * otherwise:
* accept: 1 if accept many, 0 otherwise * accept: 1 if accept many, 0 otherwise
* read: bytes to read when event is ready, -1 if not known
*/ */
#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)
int available; int available;
#else
unsigned available:1;
#endif
ngx_event_handler_pt handler; ngx_event_handler_pt handler;
+133 -62
View File
@@ -130,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;
@@ -164,7 +165,6 @@ ngx_ssl_init(ngx_log_t *log)
#endif #endif
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef SSL_OP_NO_COMPRESSION #ifndef SSL_OP_NO_COMPRESSION
{ {
/* /*
@@ -181,7 +181,6 @@ ngx_ssl_init(ngx_log_t *log)
(void) sk_SSL_COMP_pop(ssl_comp_methods); (void) sk_SSL_COMP_pop(ssl_comp_methods);
} }
} }
#endif
#endif #endif
ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
@@ -215,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) {
@@ -912,13 +918,6 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR; return NGX_ERROR;
} }
/*
* before 0.9.7h and 0.9.8 SSL_load_client_CA_file()
* always leaved an error in the error queue
*/
ERR_clear_error();
SSL_CTX_set_client_CA_list(ssl->ctx, list); SSL_CTX_set_client_CA_list(ssl->ctx, list);
return NGX_OK; return NGX_OK;
@@ -929,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) {
@@ -1084,8 +1086,8 @@ ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
* added to wbio, and set buffer size. * added to wbio, and set buffer size.
*/ */
rbio = SSL_get_rbio((ngx_ssl_conn_t *) ssl_conn); rbio = SSL_get_rbio(ssl_conn);
wbio = SSL_get_wbio((ngx_ssl_conn_t *) ssl_conn); wbio = SSL_get_wbio(ssl_conn);
if (rbio != wbio) { if (rbio != wbio) {
(void) BIO_set_write_buffer_size(wbio, NGX_SSL_BUFSIZE); (void) BIO_set_write_buffer_size(wbio, NGX_SSL_BUFSIZE);
@@ -1368,7 +1370,6 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
ngx_int_t ngx_int_t
ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name) ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
#ifndef OPENSSL_NO_ECDH #ifndef OPENSSL_NO_ECDH
/* /*
@@ -1442,7 +1443,6 @@ ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
EC_KEY_free(ecdh); EC_KEY_free(ecdh);
#endif #endif
#endif
#endif #endif
return NGX_OK; return NGX_OK;
@@ -1614,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) {
@@ -1621,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);
@@ -1641,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;
@@ -1661,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;
} }
@@ -1730,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);
@@ -1764,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;
@@ -1772,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;
} }
@@ -1942,6 +1973,10 @@ ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl, off_t limit)
last += n; last += n;
bytes += n; bytes += n;
if (!c->read->ready) {
return bytes;
}
if (last == b->end) { if (last == b->end) {
cl = cl->next; cl = cl->next;
@@ -2019,6 +2054,47 @@ ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
if (size == 0) { if (size == 0) {
c->read->ready = 1; c->read->ready = 1;
if (c->read->available >= 0) {
c->read->available -= bytes;
/*
* there can be data buffered at SSL layer,
* so we post an event to continue reading on the next
* iteration of the event loop
*/
if (c->read->available < 0) {
c->read->available = 0;
c->read->ready = 0;
if (c->read->posted) {
ngx_delete_posted_event(c->read);
}
ngx_post_event(c->read, &ngx_posted_next_events);
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_read: avail:%d", c->read->available);
} else {
#if (NGX_HAVE_FIONREAD)
if (ngx_socket_nread(c->fd, &c->read->available) == -1) {
c->read->error = 1;
ngx_connection_error(c, ngx_socket_errno,
ngx_socket_nread_n " failed");
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_read: avail:%d", c->read->available);
#endif
}
return bytes; return bytes;
} }
@@ -2747,6 +2823,9 @@ 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)) {
/* /*
@@ -2785,28 +2864,38 @@ ngx_ssl_shutdown(ngx_connection_t *c)
ngx_ssl_clear_error(c->log); ngx_ssl_clear_error(c->log);
tries = 2;
for ( ;; ) {
/*
* 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.
*/
n = SSL_shutdown(c->ssl->connection); n = SSL_shutdown(c->ssl->connection);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
sslerr = 0; if (n == 1) {
/* 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);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_get_error: %d", sslerr);
}
if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
SSL_free(c->ssl->connection); SSL_free(c->ssl->connection);
c->ssl = NULL; c->ssl = NULL;
return NGX_OK; return NGX_OK;
} }
if (n == 0 && tries-- > 1) {
continue;
}
/* before 0.9.8m SSL_shutdown() returned 0 instead of -1 on errors */
sslerr = SSL_get_error(c->ssl->connection, n);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
"SSL_get_error: %d", sslerr);
if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
c->read->handler = ngx_ssl_shutdown_handler; c->read->handler = ngx_ssl_shutdown_handler;
c->write->handler = ngx_ssl_shutdown_handler; c->write->handler = ngx_ssl_shutdown_handler;
@@ -2819,13 +2908,18 @@ ngx_ssl_shutdown(ngx_connection_t *c)
return NGX_ERROR; return NGX_ERROR;
} }
if (sslerr == SSL_ERROR_WANT_READ) { ngx_add_timer(c->read, 3000);
ngx_add_timer(c->read, 30000);
}
return NGX_AGAIN; 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; err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed"); ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
@@ -2835,6 +2929,7 @@ ngx_ssl_shutdown(ngx_connection_t *c)
return NGX_ERROR; return NGX_ERROR;
} }
}
static void static void
@@ -2875,6 +2970,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
if (sslerr == SSL_ERROR_SYSCALL) { if (sslerr == SSL_ERROR_SYSCALL) {
if (err == NGX_ECONNRESET if (err == NGX_ECONNRESET
#if (NGX_WIN32)
|| err == NGX_ECONNABORTED
#endif
|| err == NGX_EPIPE || err == NGX_EPIPE
|| err == NGX_ENOTCONN || err == NGX_ENOTCONN
|| err == NGX_ETIMEDOUT || err == NGX_ETIMEDOUT
@@ -3433,17 +3531,8 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
} }
} }
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length); session_id = (u_char *) SSL_SESSION_get_id(sess, &session_id_length);
#else
session_id = sess->session_id;
session_id_length = sess->session_id_length;
#endif
#if (NGX_PTR_SIZE == 8) #if (NGX_PTR_SIZE == 8)
id = sess_id->sess_id; id = sess_id->sess_id;
@@ -3519,13 +3608,10 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
#endif #endif
u_char *id, int len, int *copy) u_char *id, int len, int *copy)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x0090707fL
const
#endif
u_char *p;
size_t slen; size_t slen;
uint32_t hash; uint32_t hash;
ngx_int_t rc; ngx_int_t rc;
const u_char *p;
ngx_shm_zone_t *shm_zone; ngx_shm_zone_t *shm_zone;
ngx_slab_pool_t *shpool; ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node, *sentinel; ngx_rbtree_node_t *node, *sentinel;
@@ -3647,17 +3733,8 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
cache = shm_zone->data; cache = shm_zone->data;
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
id = (u_char *) SSL_SESSION_get_id(sess, &len); id = (u_char *) SSL_SESSION_get_id(sess, &len);
#else
id = sess->session_id;
len = sess->session_id_length;
#endif
hash = ngx_crc32_short(id, len); hash = ngx_crc32_short(id, len);
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
@@ -4456,17 +4533,8 @@ ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
return NGX_OK; return NGX_OK;
} }
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
buf = (u_char *) SSL_SESSION_get_id(sess, &len); buf = (u_char *) SSL_SESSION_get_id(sess, &len);
#else
buf = sess->session_id;
len = sess->session_id_length;
#endif
s->len = 2 * len; s->len = 2 * len;
s->data = ngx_pnalloc(pool, 2 * len); s->data = ngx_pnalloc(pool, 2 * len);
if (s->data == NULL) { if (s->data == NULL) {
@@ -4956,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) {
if (ngx_ssl_ocsp_get_status(c, &str) == NGX_OK) {
ngx_str_set(s, "SUCCESS"); ngx_str_set(s, "SUCCESS");
return NGX_OK; return NGX_OK;
} }
} else {
str = X509_verify_cert_error_string(rc); 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
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;
@@ -96,6 +99,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_ssl_ocsp_t *ocsp;
u_char early_buf; u_char early_buf;
unsigned handshaked:1; unsigned handshaked:1;
@@ -106,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;
@@ -193,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);
@@ -294,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;
+1060 -171
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,140 +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)
{ {
#if OPENSSL_VERSION_NUMBER >= 0x0090707fL time_t now;
const
#endif
u_char *p;
int n;
size_t len;
time_t now, valid;
ngx_str_t response; ngx_str_t response;
X509_STORE *store;
STACK_OF(X509) *chain;
OCSP_CERTID *id;
OCSP_RESPONSE *ocsp;
OCSP_BASICRESP *basic;
ngx_ssl_stapling_t *staple; 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) {
@@ -731,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,
@@ -748,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;
@@ -758,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);
} }
@@ -823,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;
} }
@@ -887,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)
{ {
@@ -912,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;
@@ -1026,15 +1499,16 @@ 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;
@@ -1044,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;
@@ -1057,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;
if (ctx->timeout) {
ngx_add_timer(ctx->peer.connection->read, ctx->timeout); ngx_add_timer(ctx->peer.connection->read, ctx->timeout);
ngx_add_timer(ctx->peer.connection->write, 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);
@@ -1083,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;
} }
@@ -1092,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;
} }
@@ -1114,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);
} }
} }
@@ -1137,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;
} }
@@ -1161,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;
} }
@@ -1192,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);
} }
@@ -1834,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)
{ {
@@ -1894,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
+33 -1
View File
@@ -172,7 +172,11 @@ ngx_event_pipe_read_upstream(ngx_event_pipe_t *p)
*/ */
if (p->upstream->read->available == 0 if (p->upstream->read->available == 0
&& p->upstream->read->pending_eof) && p->upstream->read->pending_eof
#if (NGX_SSL)
&& !p->upstream->ssl
#endif
)
{ {
p->upstream->read->ready = 0; p->upstream->read->ready = 0;
p->upstream->read->eof = 1; p->upstream->read->eof = 1;
@@ -956,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;
@@ -983,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;
+25
View File
@@ -11,6 +11,7 @@
ngx_queue_t ngx_posted_accept_events; ngx_queue_t ngx_posted_accept_events;
ngx_queue_t ngx_posted_next_events;
ngx_queue_t ngx_posted_events; ngx_queue_t ngx_posted_events;
@@ -33,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);
}
+2
View File
@@ -39,9 +39,11 @@
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;
extern ngx_queue_t ngx_posted_next_events;
extern ngx_queue_t ngx_posted_events; extern ngx_queue_t ngx_posted_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;
} }
+118 -10
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;
@@ -2076,13 +2079,31 @@ 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");
b->last = b->pos + f->rest;
p->upstream_done = 1;
break; 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,15 +2604,29 @@ 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;
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; break;
} }
f->rest -= b->last - b->pos;
}
}
return NGX_OK; return NGX_OK;
} }
+234 -30
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,10 +534,22 @@ 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 (glcf->grpc_lengths == NULL) {
ctx->host = glcf->host;
#if (NGX_HTTP_SSL) #if (NGX_HTTP_SSL)
u->ssl = (glcf->upstream.ssl != NULL); u->ssl = (glcf->upstream.ssl != NULL);
@@ -541,6 +563,12 @@ ngx_http_grpc_handler(ngx_http_request_t *r)
ngx_str_set(&u->schema, "grpc://"); ngx_str_set(&u->schema, "grpc://");
#endif #endif
} else {
if (ngx_http_grpc_eval(r, ctx, glcf) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
}
u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module; u->output.tag = (ngx_buf_tag_t) &ngx_http_grpc_module;
u->conf = &glcf->upstream; u->conf = &glcf->upstream;
@@ -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,13 +2173,23 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR; return NGX_ERROR;
} }
if (ctx->error || !ctx->done) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream rejected request with error %ui", "upstream rejected request with error %ui",
ctx->error); 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) {
rc = ngx_http_grpc_parse_goaway(r, ctx, b); rc = ngx_http_grpc_parse_goaway(r, ctx, b);
@@ -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;
} }
@@ -4540,15 +4716,51 @@ ngx_http_grpc_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *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_uint_t n;
ngx_http_core_loc_conf_t *clcf; 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;
} }
+8 -111
View File
@@ -55,44 +55,23 @@ typedef struct {
unsigned redo:1; unsigned redo:1;
unsigned done:1; unsigned done:1;
unsigned nomem:1; unsigned nomem:1;
unsigned gzheader:1;
unsigned buffering:1; unsigned buffering:1;
unsigned intel:1; unsigned intel:1;
size_t zin; size_t zin;
size_t zout; size_t zout;
uint32_t crc32;
z_stream zstream; z_stream zstream;
ngx_http_request_t *request; ngx_http_request_t *request;
} ngx_http_gzip_ctx_t; } ngx_http_gzip_ctx_t;
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
struct gztrailer {
uint32_t crc32;
uint32_t zlen;
};
#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */
struct gztrailer {
u_char crc32[4];
u_char zlen[4];
};
#endif
static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, static void ngx_http_gzip_filter_memory(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx); ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx,
ngx_chain_t *in); ngx_chain_t *in);
static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx); ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r,
ngx_http_gzip_ctx_t *ctx); ngx_http_gzip_ctx_t *ctx);
static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r,
@@ -446,12 +425,6 @@ ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
return ctx->busy ? NGX_AGAIN : NGX_OK; return ctx->busy ? NGX_AGAIN : NGX_OK;
} }
if (!ctx->gzheader) {
if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) {
goto failed;
}
}
rc = ngx_http_next_body_filter(r, ctx->out); rc = ngx_http_next_body_filter(r, ctx->out);
if (rc == NGX_ERROR) { if (rc == NGX_ERROR) {
@@ -643,7 +616,7 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
ctx->zstream.opaque = ctx; ctx->zstream.opaque = ctx;
rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED, rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED,
- ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY); ctx->wbits + 16, ctx->memlevel, Z_DEFAULT_STRATEGY);
if (rc != Z_OK) { if (rc != Z_OK) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
@@ -652,45 +625,12 @@ ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r,
} }
ctx->last_out = &ctx->out; ctx->last_out = &ctx->out;
ctx->crc32 = crc32(0L, Z_NULL, 0);
ctx->flush = Z_NO_FLUSH; ctx->flush = Z_NO_FLUSH;
return NGX_OK; return NGX_OK;
} }
static ngx_int_t
ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{
ngx_buf_t *b;
ngx_chain_t *cl;
static u_char gzheader[10] =
{ 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_ERROR;
}
b->memory = 1;
b->pos = gzheader;
b->last = b->pos + 10;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b;
cl->next = ctx->out;
ctx->out = cl;
ctx->gzheader = 1;
return NGX_OK;
}
static ngx_int_t static ngx_int_t
ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
{ {
@@ -743,14 +683,9 @@ ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
} else if (ctx->in_buf->flush) { } else if (ctx->in_buf->flush) {
ctx->flush = Z_SYNC_FLUSH; ctx->flush = Z_SYNC_FLUSH;
}
if (ctx->zstream.avail_in) { } else if (ctx->zstream.avail_in == 0) {
/* ctx->flush == Z_NO_FLUSH */
ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in,
ctx->zstream.avail_in);
} else if (ctx->flush == Z_NO_FLUSH) {
return NGX_AGAIN; return NGX_AGAIN;
} }
@@ -843,7 +778,7 @@ ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx)
ctx->out_buf->last = ctx->zstream.next_out; ctx->out_buf->last = ctx->zstream.next_out;
if (ctx->zstream.avail_out == 0) { if (ctx->zstream.avail_out == 0 && rc != Z_STREAM_END) {
/* zlib wants to output some more gzipped data */ /* zlib wants to output some more gzipped data */
@@ -935,10 +870,9 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
int rc; int rc;
ngx_buf_t *b; ngx_buf_t *b;
ngx_chain_t *cl; ngx_chain_t *cl;
struct gztrailer *trailer;
ctx->zin = ctx->zstream.total_in; ctx->zin = ctx->zstream.total_in;
ctx->zout = 10 + ctx->zstream.total_out + 8; ctx->zout = ctx->zstream.total_out;
rc = deflateEnd(&ctx->zstream); rc = deflateEnd(&ctx->zstream);
@@ -955,55 +889,18 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r,
return NGX_ERROR; return NGX_ERROR;
} }
cl->buf = ctx->out_buf; b = ctx->out_buf;
cl->next = NULL;
*ctx->last_out = cl;
ctx->last_out = &cl->next;
if (ctx->zstream.avail_out >= 8) { if (ngx_buf_size(b) == 0) {
trailer = (struct gztrailer *) ctx->out_buf->last; b->temporary = 0;
ctx->out_buf->last += 8;
ctx->out_buf->last_buf = 1;
} else {
b = ngx_create_temp_buf(r->pool, 8);
if (b == NULL) {
return NGX_ERROR;
} }
b->last_buf = 1; b->last_buf = 1;
cl = ngx_alloc_chain_link(r->pool);
if (cl == NULL) {
return NGX_ERROR;
}
cl->buf = b; cl->buf = b;
cl->next = NULL; cl->next = NULL;
*ctx->last_out = cl; *ctx->last_out = cl;
ctx->last_out = &cl->next; ctx->last_out = &cl->next;
trailer = (struct gztrailer *) b->pos;
b->last += 8;
}
#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED)
trailer->crc32 = ctx->crc32;
trailer->zlen = ctx->zin;
#else
trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff);
trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff);
trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff);
trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff);
trailer->zlen[0] = (u_char) (ctx->zin & 0xff);
trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff);
trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff);
trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff);
#endif
ctx->zstream.avail_in = 0; ctx->zstream.avail_in = 0;
ctx->zstream.avail_out = 0; ctx->zstream.avail_out = 0;
+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;
+126 -38
View File
@@ -10,6 +10,11 @@
#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;
@@ -25,7 +30,14 @@ typedef struct {
typedef struct { typedef struct {
ngx_rbtree_t *rbtree; ngx_rbtree_t rbtree;
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_complex_value_t key;
} ngx_http_limit_conn_ctx_t; } ngx_http_limit_conn_ctx_t;
@@ -40,6 +52,7 @@ 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)
{ {
+98 -6
View File
@@ -10,6 +10,13 @@
#include <ngx_http.h> #include <ngx_http.h>
#define NGX_HTTP_LIMIT_REQ_PASSED 1
#define NGX_HTTP_LIMIT_REQ_DELAYED 2
#define NGX_HTTP_LIMIT_REQ_REJECTED 3
#define NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN 4
#define NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN 5
typedef struct { typedef struct {
u_char color; u_char color;
u_char dummy; u_char dummy;
@@ -53,6 +60,7 @@ typedef struct {
ngx_uint_t limit_log_level; ngx_uint_t limit_log_level;
ngx_uint_t delay_log_level; ngx_uint_t delay_log_level;
ngx_uint_t status_code; ngx_uint_t status_code;
ngx_flag_t dry_run;
} ngx_http_limit_req_conf_t; } ngx_http_limit_req_conf_t;
@@ -64,6 +72,8 @@ static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits,
static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx,
ngx_uint_t n); ngx_uint_t n);
static ngx_int_t ngx_http_limit_req_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf);
static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent,
void *child); void *child);
@@ -71,6 +81,7 @@ static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
static ngx_int_t ngx_http_limit_req_add_variables(ngx_conf_t *cf);
static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf);
@@ -118,12 +129,19 @@ static ngx_command_t ngx_http_limit_req_commands[] = {
offsetof(ngx_http_limit_req_conf_t, status_code), offsetof(ngx_http_limit_req_conf_t, status_code),
&ngx_http_limit_req_status_bounds }, &ngx_http_limit_req_status_bounds },
{ ngx_string("limit_req_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_req_conf_t, dry_run),
NULL },
ngx_null_command ngx_null_command
}; };
static ngx_http_module_t ngx_http_limit_req_module_ctx = { static ngx_http_module_t ngx_http_limit_req_module_ctx = {
NULL, /* preconfiguration */ ngx_http_limit_req_add_variables, /* preconfiguration */
ngx_http_limit_req_init, /* postconfiguration */ ngx_http_limit_req_init, /* postconfiguration */
NULL, /* create main configuration */ NULL, /* create main configuration */
@@ -153,6 +171,24 @@ ngx_module_t ngx_http_limit_req_module = {
}; };
static ngx_http_variable_t ngx_http_limit_req_vars[] = {
{ ngx_string("limit_req_status"), NULL,
ngx_http_limit_req_status_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
ngx_http_null_variable
};
static ngx_str_t ngx_http_limit_req_status[] = {
ngx_string("PASSED"),
ngx_string("DELAYED"),
ngx_string("REJECTED"),
ngx_string("DELAYED_DRY_RUN"),
ngx_string("REJECTED_DRY_RUN")
};
static ngx_int_t static ngx_int_t
ngx_http_limit_req_handler(ngx_http_request_t *r) ngx_http_limit_req_handler(ngx_http_request_t *r)
{ {
@@ -165,7 +201,7 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
ngx_http_limit_req_conf_t *lrcf; ngx_http_limit_req_conf_t *lrcf;
ngx_http_limit_req_limit_t *limit, *limits; ngx_http_limit_req_limit_t *limit, *limits;
if (r->main->limit_req_set) { if (r->main->limit_req_status) {
return NGX_DECLINED; return NGX_DECLINED;
} }
@@ -224,13 +260,12 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
return NGX_DECLINED; return NGX_DECLINED;
} }
r->main->limit_req_set = 1;
if (rc == NGX_BUSY || rc == NGX_ERROR) { if (rc == NGX_BUSY || rc == NGX_ERROR) {
if (rc == NGX_BUSY) { if (rc == NGX_BUSY) {
ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, ngx_log_error(lrcf->limit_log_level, r->connection->log, 0,
"limiting requests, excess: %ui.%03ui by zone \"%V\"", "limiting requests%s, excess: %ui.%03ui by zone \"%V\"",
lrcf->dry_run ? ", dry run" : "",
excess / 1000, excess % 1000, excess / 1000, excess % 1000,
&limit->shm_zone->shm.name); &limit->shm_zone->shm.name);
} }
@@ -251,6 +286,13 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
ctx->node = NULL; ctx->node = NULL;
} }
if (lrcf->dry_run) {
r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED_DRY_RUN;
return NGX_DECLINED;
}
r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_REJECTED;
return lrcf->status_code; return lrcf->status_code;
} }
@@ -263,13 +305,22 @@ ngx_http_limit_req_handler(ngx_http_request_t *r)
delay = ngx_http_limit_req_account(limits, n, &excess, &limit); delay = ngx_http_limit_req_account(limits, n, &excess, &limit);
if (!delay) { if (!delay) {
r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_PASSED;
return NGX_DECLINED; return NGX_DECLINED;
} }
ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, ngx_log_error(lrcf->delay_log_level, r->connection->log, 0,
"delaying request, excess: %ui.%03ui, by zone \"%V\"", "delaying request%s, excess: %ui.%03ui, by zone \"%V\"",
lrcf->dry_run ? ", dry run" : "",
excess / 1000, excess % 1000, &limit->shm_zone->shm.name); excess / 1000, excess % 1000, &limit->shm_zone->shm.name);
if (lrcf->dry_run) {
r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED_DRY_RUN;
return NGX_DECLINED;
}
r->main->limit_req_status = NGX_HTTP_LIMIT_REQ_DELAYED;
if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
} }
@@ -693,6 +744,25 @@ ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data)
} }
static ngx_int_t
ngx_http_limit_req_status_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->main->limit_req_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_req_status[r->main->limit_req_status - 1].len;
v->data = ngx_http_limit_req_status[r->main->limit_req_status - 1].data;
return NGX_OK;
}
static void * static void *
ngx_http_limit_req_create_conf(ngx_conf_t *cf) ngx_http_limit_req_create_conf(ngx_conf_t *cf)
{ {
@@ -711,6 +781,7 @@ ngx_http_limit_req_create_conf(ngx_conf_t *cf)
conf->limit_log_level = NGX_CONF_UNSET_UINT; conf->limit_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;
} }
@@ -735,6 +806,8 @@ ngx_http_limit_req_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;
} }
@@ -974,6 +1047,25 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
} }
static ngx_int_t
ngx_http_limit_req_add_variables(ngx_conf_t *cf)
{
ngx_http_variable_t *var, *v;
for (v = ngx_http_limit_req_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_req_init(ngx_conf_t *cf) ngx_http_limit_req_init(ngx_conf_t *cf)
{ {
+5 -2
View File
@@ -485,7 +485,8 @@ 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)
@@ -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;
} }
+47 -11
View File
@@ -700,8 +700,9 @@ ngx_http_range_singlepart_body(ngx_http_request_t *r,
ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
{ {
off_t start, last; off_t start, last;
ngx_int_t rc;
ngx_buf_t *buf; ngx_buf_t *buf;
ngx_chain_t *out, *cl, **ll; ngx_chain_t *out, *cl, *tl, **ll;
ngx_http_range_t *range; ngx_http_range_t *range;
out = NULL; out = NULL;
@@ -721,8 +722,22 @@ ngx_http_range_singlepart_body(ngx_http_request_t *r,
"http range body buf: %O-%O", start, last); "http range body buf: %O-%O", start, last);
if (ngx_buf_special(buf)) { if (ngx_buf_special(buf)) {
*ll = cl;
ll = &cl->next; if (range->end <= start) {
continue;
}
tl = ngx_alloc_chain_link(r->pool);
if (tl == NULL) {
return NGX_ERROR;
}
tl->buf = buf;
tl->next = NULL;
*ll = tl;
ll = &tl->next;
continue; continue;
} }
@@ -764,21 +779,42 @@ ngx_http_range_singlepart_body(ngx_http_request_t *r,
buf->last_buf = (r == r->main) ? 1 : 0; buf->last_buf = (r == r->main) ? 1 : 0;
buf->last_in_chain = 1; buf->last_in_chain = 1;
*ll = cl;
cl->next = NULL;
break; tl = ngx_alloc_chain_link(r->pool);
if (tl == NULL) {
return NGX_ERROR;
} }
*ll = cl; tl->buf = buf;
ll = &cl->next; tl->next = NULL;
*ll = tl;
ll = &tl->next;
continue;
} }
if (out == NULL) { tl = ngx_alloc_chain_link(r->pool);
return NGX_OK; if (tl == NULL) {
return NGX_ERROR;
} }
return ngx_http_next_body_filter(r, out); tl->buf = buf;
tl->next = NULL;
*ll = tl;
ll = &tl->next;
}
rc = ngx_http_next_body_filter(r, out);
while (out) {
cl = out;
out = out->next;
ngx_free_chain(r->pool, cl);
}
return rc;
} }
+3 -4
View File
@@ -180,12 +180,11 @@ ngx_http_realip_handler(ngx_http_request_t *r)
case NGX_HTTP_REALIP_PROXY: case NGX_HTTP_REALIP_PROXY:
value = &r->connection->proxy_protocol_addr; if (r->connection->proxy_protocol == NULL) {
if (value->len == 0) {
return NGX_DECLINED; return NGX_DECLINED;
} }
value = &r->connection->proxy_protocol->src_addr;
xfwd = NULL; xfwd = NULL;
break; break;
@@ -238,7 +237,7 @@ found:
!= NGX_DECLINED) != NGX_DECLINED)
{ {
if (rlcf->type == NGX_HTTP_REALIP_PROXY) { if (rlcf->type == NGX_HTTP_REALIP_PROXY) {
ngx_inet_set_port(addr.sockaddr, c->proxy_protocol_port); ngx_inet_set_port(addr.sockaddr, c->proxy_protocol->src_port);
} }
return ngx_http_realip_set_addr(r, &addr); return ngx_http_realip_set_addr(r, &addr);
@@ -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;
@@ -1254,9 +1254,9 @@ ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx)
case '-': case '-':
state = ssi_error_end0_state; state = ssi_error_end0_state;
ctx->param->key.data[ctx->param->key.len++] = ch;
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid \"%V\" parameter in \"%V\" SSI command", "unexpected \"-\" symbol after \"%V\" "
"parameter in \"%V\" SSI command",
&ctx->param->key, &ctx->command); &ctx->param->key, &ctx->command);
break; break;
+148 -2
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, "");
@@ -841,7 +880,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->client_certificate.len == 0 && conf->verify != 3) { if (conf->client_certificate.len == 0 && conf->verify != 3) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0, ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no ssl_client_certificate for ssl_client_verify"); "no ssl_client_certificate for ssl_verify_client");
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
@@ -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,12 +1339,13 @@ 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 (sscf->stapling) {
if (ngx_ssl_stapling_resolver(cf, &sscf->ssl, clcf->resolver, if (ngx_ssl_stapling_resolver(cf, &sscf->ssl, clcf->resolver,
clcf->resolver_timeout) clcf->resolver_timeout)
!= NGX_OK) != NGX_OK)
@@ -1218,6 +1354,16 @@ ngx_http_ssl_init(ngx_conf_t *cf)
} }
} }
if (sscf->ocsp) {
if (ngx_ssl_ocsp_resolver(cf, &sscf->ssl, clcf->resolver,
clcf->resolver_timeout)
!= NGX_OK)
{
return NGX_ERROR;
}
}
}
if (cmcf->ports == NULL) { if (cmcf->ports == NULL) {
return NGX_OK; return NGX_OK;
} }
+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 = '/';
@@ -178,7 +178,7 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_rlock(hp->rrp.peers); ngx_http_upstream_rr_peers_rlock(hp->rrp.peers);
if (hp->tries > 20 || hp->rrp.peers->single) { if (hp->tries > 20 || hp->rrp.peers->single || hp->key.len == 0) {
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return hp->get_rr_peer(pc, &hp->rrp); return hp->get_rr_peer(pc, &hp->rrp);
} }
@@ -509,7 +509,7 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
ngx_http_upstream_rr_peers_wlock(hp->rrp.peers); ngx_http_upstream_rr_peers_wlock(hp->rrp.peers);
if (hp->tries > 20 || hp->rrp.peers->single) { if (hp->tries > 20 || hp->rrp.peers->single || hp->key.len == 0) {
ngx_http_upstream_rr_peers_unlock(hp->rrp.peers); ngx_http_upstream_rr_peers_unlock(hp->rrp.peers);
return hp->get_rr_peer(pc, &hp->rrp); return hp->get_rr_peer(pc, &hp->rrp);
} }
@@ -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;
} }
@@ -628,7 +629,7 @@ static ngx_int_t
ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
ngx_array_t *params, ngx_uint_t final) ngx_array_t *params, ngx_uint_t final)
{ {
u_char *p, *last, *value, *dst, *src, **s; u_char *p, *value, *dst, *src, **s;
size_t len; size_t len;
ngx_uint_t i; ngx_uint_t i;
ngx_str_t string; ngx_str_t string;
@@ -698,8 +699,6 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
ngx_memcpy(p, string.data, string.len + 1); ngx_memcpy(p, string.data, string.len + 1);
} }
last = p + string.len;
while (p && *p) { while (p && *p) {
value = p; value = p;
@@ -729,7 +728,7 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
*p++ = '\0'; *p++ = '\0';
} else { } else {
len = last - value; len = ngx_strlen(value);
} }
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+248 -84
View File
@@ -15,8 +15,10 @@
#include "XSUB.h" #include "XSUB.h"
#define ngx_http_perl_set_request(r) \ #define ngx_http_perl_set_request(r, ctx) \
r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) \
ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \
r = ctx->request
#define ngx_http_perl_set_targ(p, len) \ #define ngx_http_perl_set_targ(p, len) \
@@ -64,14 +66,12 @@ ngx_http_perl_sv2str(pTHX_ ngx_http_request_t *r, ngx_str_t *s, SV *sv)
static ngx_int_t static ngx_int_t
ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) ngx_http_perl_output(ngx_http_request_t *r, ngx_http_perl_ctx_t *ctx,
ngx_buf_t *b)
{ {
ngx_chain_t out; ngx_chain_t out;
#if (NGX_HTTP_SSI) #if (NGX_HTTP_SSI)
ngx_chain_t *cl; ngx_chain_t *cl;
ngx_http_perl_ctx_t *ctx;
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ctx->ssi) { if (ctx->ssi) {
cl = ngx_alloc_chain_link(r->pool); cl = ngx_alloc_chain_link(r->pool);
@@ -106,8 +106,13 @@ status(r, code)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->variable) {
croak("status(): cannot be used in variable handler");
}
r->headers_out.status = SvIV(ST(1)); r->headers_out.status = SvIV(ST(1));
@@ -122,9 +127,27 @@ send_http_header(r, ...)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *sv; SV *sv;
ngx_int_t rc;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->error) {
croak("send_http_header(): called after error");
}
if (ctx->variable) {
croak("send_http_header(): cannot be used in variable handler");
}
if (ctx->header_sent) {
croak("send_http_header(): header already sent");
}
if (ctx->redirect_uri.len) {
croak("send_http_header(): cannot be used with internal_redirect()");
}
if (r->headers_out.status == 0) { if (r->headers_out.status == 0) {
r->headers_out.status = NGX_HTTP_OK; r->headers_out.status = NGX_HTTP_OK;
@@ -136,18 +159,30 @@ send_http_header(r, ...)
if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv) if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv)
!= NGX_OK) != NGX_OK)
{ {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_http_perl_sv2str() failed");
} }
r->headers_out.content_type_len = r->headers_out.content_type.len; r->headers_out.content_type_len = r->headers_out.content_type.len;
} else { } else {
if (ngx_http_set_content_type(r) != NGX_OK) { if (ngx_http_set_content_type(r) != NGX_OK) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_http_set_content_type() failed");
} }
} }
(void) ngx_http_send_header(r); ctx->header_sent = 1;
r->disable_not_modified = 1;
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK) {
ctx->error = 1;
ctx->status = rc;
croak("ngx_http_send_header() failed");
}
void void
@@ -156,8 +191,9 @@ header_only(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
sv_upgrade(TARG, SVt_IV); sv_upgrade(TARG, SVt_IV);
sv_setiv(TARG, r->header_only); sv_setiv(TARG, r->header_only);
@@ -171,8 +207,9 @@ uri(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->uri.data, r->uri.len); ngx_http_perl_set_targ(r->uri.data, r->uri.len);
ST(0) = TARG; ST(0) = TARG;
@@ -184,8 +221,9 @@ args(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->args.data, r->args.len); ngx_http_perl_set_targ(r->args.data, r->args.len);
ST(0) = TARG; ST(0) = TARG;
@@ -197,8 +235,9 @@ request_method(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); ngx_http_perl_set_targ(r->method_name.data, r->method_name.len);
ST(0) = TARG; ST(0) = TARG;
@@ -210,8 +249,9 @@ remote_addr(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_perl_set_targ(r->connection->addr_text.data, ngx_http_perl_set_targ(r->connection->addr_text.data,
r->connection->addr_text.len); r->connection->addr_text.len);
@@ -224,6 +264,7 @@ header_in(r, key)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *key; SV *key;
u_char *p, *lowcase_key, *value, sep; u_char *p, *lowcase_key, *value, sep;
STRLEN len; STRLEN len;
@@ -235,7 +276,7 @@ header_in(r, key)
ngx_http_header_t *hh; ngx_http_header_t *hh;
ngx_http_core_main_conf_t *cmcf; ngx_http_core_main_conf_t *cmcf;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
key = ST(1); key = ST(1);
@@ -249,7 +290,8 @@ header_in(r, key)
lowcase_key = ngx_pnalloc(r->pool, len); lowcase_key = ngx_pnalloc(r->pool, len);
if (lowcase_key == NULL) { if (lowcase_key == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_pnalloc() failed");
} }
hash = ngx_hash_strlow(lowcase_key, p, len); hash = ngx_hash_strlow(lowcase_key, p, len);
@@ -309,7 +351,8 @@ header_in(r, key)
value = ngx_pnalloc(r->pool, size); value = ngx_pnalloc(r->pool, size);
if (value == NULL) { if (value == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_pnalloc() failed");
} }
p = value; p = value;
@@ -371,14 +414,22 @@ has_request_body(r, next)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
ngx_int_t rc;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->variable) {
croak("has_request_body(): cannot be used in variable handler");
}
if (ctx->next) {
croak("has_request_body(): another handler active");
}
if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
XSRETURN_UNDEF; XSRETURN_UNDEF;
} }
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
ctx->next = SvRV(ST(1)); ctx->next = SvRV(ST(1));
r->request_body_in_single_buf = 1; r->request_body_in_single_buf = 1;
@@ -389,7 +440,14 @@ has_request_body(r, next)
r->request_body_file_log_level = 0; r->request_body_file_log_level = 0;
} }
ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
ctx->error = 1;
ctx->status = rc;
ctx->next = NULL;
croak("ngx_http_read_client_request_body() failed");
}
sv_upgrade(TARG, SVt_IV); sv_upgrade(TARG, SVt_IV);
sv_setiv(TARG, 1); sv_setiv(TARG, 1);
@@ -403,12 +461,13 @@ request_body(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
u_char *p, *data; u_char *p, *data;
size_t len; size_t len;
ngx_buf_t *buf; ngx_buf_t *buf;
ngx_chain_t *cl; ngx_chain_t *cl;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (r->request_body == NULL if (r->request_body == NULL
|| r->request_body->temp_file || r->request_body->temp_file
@@ -436,7 +495,8 @@ request_body(r)
p = ngx_pnalloc(r->pool, len); p = ngx_pnalloc(r->pool, len);
if (p == NULL) { if (p == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_pnalloc() failed");
} }
data = p; data = p;
@@ -464,8 +524,9 @@ request_body_file(r)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (r->request_body == NULL || r->request_body->temp_file == NULL) { if (r->request_body == NULL || r->request_body->temp_file == NULL) {
XSRETURN_UNDEF; XSRETURN_UNDEF;
@@ -482,10 +543,22 @@ discard_request_body(r)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_int_t rc;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ngx_http_discard_request_body(r); if (ctx->variable) {
croak("discard_request_body(): cannot be used in variable handler");
}
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
ctx->error = 1;
ctx->status = rc;
croak("ngx_http_discard_request_body() failed");
}
void void
@@ -493,30 +566,42 @@ header_out(r, key, value)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *key; SV *key;
SV *value; SV *value;
ngx_table_elt_t *header; ngx_table_elt_t *header;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->error) {
croak("header_out(): called after error");
}
if (ctx->variable) {
croak("header_out(): cannot be used in variable handler");
}
key = ST(1); key = ST(1);
value = ST(2); value = ST(2);
header = ngx_list_push(&r->headers_out.headers); header = ngx_list_push(&r->headers_out.headers);
if (header == NULL) { if (header == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_list_push() failed");
} }
header->hash = 1; header->hash = 1;
if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
header->hash = 0; header->hash = 0;
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_http_perl_sv2str() failed");
} }
if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) { if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) {
header->hash = 0; header->hash = 0;
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_http_perl_sv2str() failed");
} }
if (header->key.len == sizeof("Content-Length") - 1 if (header->key.len == sizeof("Content-Length") - 1
@@ -540,19 +625,19 @@ filename(r)
CODE: CODE:
dXSTARG; dXSTARG;
size_t root;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
size_t root;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ctx->filename.data) { if (ctx->filename.data) {
goto done; goto done;
} }
if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) { if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_http_map_uri_to_path() failed");
} }
ctx->filename.len--; ctx->filename.len--;
@@ -570,14 +655,28 @@ print(r, ...)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *sv; SV *sv;
int i; int i;
u_char *p; u_char *p;
size_t size; size_t size;
STRLEN len; STRLEN len;
ngx_int_t rc;
ngx_buf_t *b; ngx_buf_t *b;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->error) {
croak("print(): called after error");
}
if (ctx->variable) {
croak("print(): cannot be used in variable handler");
}
if (!ctx->header_sent) {
croak("print(): header not sent");
}
if (items == 2) { if (items == 2) {
@@ -602,7 +701,8 @@ print(r, ...)
b = ngx_calloc_buf(r->pool); b = ngx_calloc_buf(r->pool);
if (b == NULL) { if (b == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_calloc_buf() failed");
} }
b->memory = 1; b->memory = 1;
@@ -642,7 +742,8 @@ print(r, ...)
b = ngx_create_temp_buf(r->pool, size); b = ngx_create_temp_buf(r->pool, size);
if (b == NULL) { if (b == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_create_temp_buf() failed");
} }
for (i = 1; i < items; i++) { for (i = 1; i < items; i++) {
@@ -658,7 +759,12 @@ print(r, ...)
out: out:
(void) ngx_http_perl_output(r, b); rc = ngx_http_perl_output(r, ctx, b);
if (rc == NGX_ERROR) {
ctx->error = 1;
croak("ngx_http_perl_output() failed");
}
void void
@@ -666,15 +772,29 @@ sendfile(r, filename, offset = -1, bytes = 0)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
char *filename; char *filename;
off_t offset; off_t offset;
size_t bytes; size_t bytes;
ngx_int_t rc;
ngx_str_t path; ngx_str_t path;
ngx_buf_t *b; ngx_buf_t *b;
ngx_open_file_info_t of; ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->error) {
croak("sendfile(): called after error");
}
if (ctx->variable) {
croak("sendfile(): cannot be used in variable handler");
}
if (!ctx->header_sent) {
croak("sendfile(): header not sent");
}
filename = SvPV_nolen(ST(1)); filename = SvPV_nolen(ST(1));
@@ -687,19 +807,22 @@ sendfile(r, filename, offset = -1, bytes = 0)
b = ngx_calloc_buf(r->pool); b = ngx_calloc_buf(r->pool);
if (b == NULL) { if (b == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_calloc_buf() failed");
} }
b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
if (b->file == NULL) { if (b->file == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_pcalloc() failed");
} }
path.len = ngx_strlen(filename); path.len = ngx_strlen(filename);
path.data = ngx_pnalloc(r->pool, path.len + 1); path.data = ngx_pnalloc(r->pool, path.len + 1);
if (path.data == NULL) { if (path.data == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_pnalloc() failed");
} }
(void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1); (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1);
@@ -716,19 +839,23 @@ sendfile(r, filename, offset = -1, bytes = 0)
of.events = clcf->open_file_cache_events; of.events = clcf->open_file_cache_events;
if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_http_set_disable_symlinks() failed");
} }
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK) != NGX_OK)
{ {
if (of.err == 0) { if (of.err == 0) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_open_cached_file() failed");
} }
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
"%s \"%s\" failed", of.failed, filename); "%s \"%s\" failed", of.failed, filename);
XSRETURN_EMPTY;
ctx->error = 1;
croak("ngx_open_cached_file() failed");
} }
if (offset == -1) { if (offset == -1) {
@@ -748,7 +875,12 @@ sendfile(r, filename, offset = -1, bytes = 0)
b->file->log = r->connection->log; b->file->log = r->connection->log;
b->file->directio = of.is_directio; b->file->directio = of.is_directio;
(void) ngx_http_perl_output(r, b); rc = ngx_http_perl_output(r, ctx, b);
if (rc == NGX_ERROR) {
ctx->error = 1;
croak("ngx_http_perl_output() failed");
}
void void
@@ -756,20 +888,40 @@ flush(r)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_int_t rc;
ngx_buf_t *b; ngx_buf_t *b;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->error) {
croak("flush(): called after error");
}
if (ctx->variable) {
croak("flush(): cannot be used in variable handler");
}
if (!ctx->header_sent) {
croak("flush(): header not sent");
}
b = ngx_calloc_buf(r->pool); b = ngx_calloc_buf(r->pool);
if (b == NULL) { if (b == NULL) {
XSRETURN_EMPTY; ctx->error = 1;
croak("ngx_calloc_buf() failed");
} }
b->flush = 1; b->flush = 1;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush");
(void) ngx_http_perl_output(r, b); rc = ngx_http_perl_output(r, ctx, b);
if (rc == NGX_ERROR) {
ctx->error = 1;
croak("ngx_http_perl_output() failed");
}
XSRETURN_EMPTY; XSRETURN_EMPTY;
@@ -779,29 +931,24 @@ internal_redirect(r, uri)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
SV *uri;
ngx_uint_t i;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
SV *uri;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->variable) {
croak("internal_redirect(): cannot be used in variable handler");
}
if (ctx->header_sent) {
croak("internal_redirect(): header already sent");
}
uri = ST(1); uri = ST(1);
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) {
XSRETURN_EMPTY; ctx->error = 1;
} croak("ngx_http_perl_sv2str() failed");
for (i = 0; i < ctx->redirect_uri.len; i++) {
if (ctx->redirect_uri.data[i] == '?') {
ctx->redirect_args.len = ctx->redirect_uri.len - (i + 1);
ctx->redirect_args.data = &ctx->redirect_uri.data[i + 1];
ctx->redirect_uri.len = i;
XSRETURN_EMPTY;
}
} }
@@ -810,8 +957,13 @@ allow_ranges(r)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->variable) {
croak("allow_ranges(): cannot be used in variable handler");
}
r->allow_ranges = 1; r->allow_ranges = 1;
@@ -822,12 +974,13 @@ unescape(r, text, type = 0)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *text; SV *text;
int type; int type;
u_char *p, *dst, *src; u_char *p, *dst, *src;
STRLEN len; STRLEN len;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
text = ST(1); text = ST(1);
@@ -835,7 +988,8 @@ unescape(r, text, type = 0)
p = ngx_pnalloc(r->pool, len + 1); p = ngx_pnalloc(r->pool, len + 1);
if (p == NULL) { if (p == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_pnalloc() failed");
} }
dst = p; dst = p;
@@ -856,16 +1010,16 @@ variable(r, name, value = NULL)
dXSTARG; dXSTARG;
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *name, *value; SV *name, *value;
u_char *p, *lowcase; u_char *p, *lowcase;
STRLEN len; STRLEN len;
ngx_str_t var, val; ngx_str_t var, val;
ngx_uint_t i, hash; ngx_uint_t i, hash;
ngx_http_perl_var_t *v; ngx_http_perl_var_t *v;
ngx_http_perl_ctx_t *ctx;
ngx_http_variable_value_t *vv; ngx_http_variable_value_t *vv;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
name = ST(1); name = ST(1);
@@ -884,7 +1038,8 @@ variable(r, name, value = NULL)
} }
if (ngx_http_perl_sv2str(aTHX_ r, &val, value) != NGX_OK) { if (ngx_http_perl_sv2str(aTHX_ r, &val, value) != NGX_OK) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_http_perl_sv2str() failed");
} }
} }
@@ -892,7 +1047,8 @@ variable(r, name, value = NULL)
lowcase = ngx_pnalloc(r->pool, len); lowcase = ngx_pnalloc(r->pool, len);
if (lowcase == NULL) { if (lowcase == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_pnalloc() failed");
} }
hash = ngx_hash_strlow(lowcase, p, len); hash = ngx_hash_strlow(lowcase, p, len);
@@ -912,13 +1068,12 @@ variable(r, name, value = NULL)
vv = ngx_http_get_variable(r, &var, hash); vv = ngx_http_get_variable(r, &var, hash);
if (vv == NULL) { if (vv == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_http_get_variable() failed");
} }
if (vv->not_found) { if (vv->not_found) {
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
if (ctx->variables) { if (ctx->variables) {
v = ctx->variables->elts; v = ctx->variables->elts;
@@ -947,13 +1102,15 @@ variable(r, name, value = NULL)
ctx->variables = ngx_array_create(r->pool, 1, ctx->variables = ngx_array_create(r->pool, 1,
sizeof(ngx_http_perl_var_t)); sizeof(ngx_http_perl_var_t));
if (ctx->variables == NULL) { if (ctx->variables == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_array_create() failed");
} }
} }
v = ngx_array_push(ctx->variables); v = ngx_array_push(ctx->variables);
if (v == NULL) { if (v == NULL) {
XSRETURN_UNDEF; ctx->error = 1;
croak("ngx_array_push() failed");
} }
v->hash = hash; v->hash = hash;
@@ -989,18 +1146,24 @@ sleep(r, sleep, next)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_msec_t sleep;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
ngx_msec_t sleep;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
if (ctx->variable) {
croak("sleep(): cannot be used in variable handler");
}
if (ctx->next) {
croak("sleep(): another handler active");
}
sleep = (ngx_msec_t) SvIV(ST(1)); sleep = (ngx_msec_t) SvIV(ST(1));
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl sleep: %M", sleep); "perl sleep: %M", sleep);
ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
ctx->next = SvRV(ST(2)); ctx->next = SvRV(ST(2));
r->connection->write->delayed = 1; r->connection->write->delayed = 1;
@@ -1015,12 +1178,13 @@ log_error(r, err, msg)
CODE: CODE:
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_perl_ctx_t *ctx;
SV *err, *msg; SV *err, *msg;
u_char *p; u_char *p;
STRLEN len; STRLEN len;
ngx_err_t e; ngx_err_t e;
ngx_http_perl_set_request(r); ngx_http_perl_set_request(r, ctx);
err = ST(1); err = ST(1);
+64 -15
View File
@@ -43,7 +43,8 @@ static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
ngx_log_t *log); ngx_log_t *log);
static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args,
ngx_str_t *handler, ngx_str_t *rv);
static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv);
static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf);
@@ -183,6 +184,7 @@ ngx_http_perl_handle_request(ngx_http_request_t *r)
SV *sub; SV *sub;
ngx_int_t rc; ngx_int_t rc;
ngx_str_t uri, args, *handler; ngx_str_t uri, args, *handler;
ngx_uint_t flags;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
ngx_http_perl_loc_conf_t *plcf; ngx_http_perl_loc_conf_t *plcf;
ngx_http_perl_main_conf_t *pmcf; ngx_http_perl_main_conf_t *pmcf;
@@ -199,6 +201,8 @@ ngx_http_perl_handle_request(ngx_http_request_t *r)
} }
ngx_http_set_ctx(r, ctx, ngx_http_perl_module); ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
ctx->request = r;
} }
pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
@@ -220,26 +224,20 @@ ngx_http_perl_handle_request(ngx_http_request_t *r)
ctx->next = NULL; ctx->next = NULL;
} }
rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler, rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sub, NULL,
NULL); handler, NULL);
} }
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"perl handler done: %i", rc); "perl handler done: %i", rc);
if (rc == NGX_DONE) {
ngx_http_finalize_request(r, rc);
return;
}
if (rc > 600) { if (rc > 600) {
rc = NGX_OK; rc = NGX_OK;
} }
if (ctx->redirect_uri.len) { if (ctx->redirect_uri.len) {
uri = ctx->redirect_uri; uri = ctx->redirect_uri;
args = ctx->redirect_args;
} else { } else {
uri.len = 0; uri.len = 0;
@@ -248,13 +246,32 @@ ngx_http_perl_handle_request(ngx_http_request_t *r)
ctx->filename.data = NULL; ctx->filename.data = NULL;
ctx->redirect_uri.len = 0; ctx->redirect_uri.len = 0;
if (rc == NGX_ERROR) {
ngx_http_finalize_request(r, rc);
return;
}
if (ctx->done || ctx->next) { if (ctx->done || ctx->next) {
ngx_http_finalize_request(r, NGX_DONE); ngx_http_finalize_request(r, NGX_DONE);
return; return;
} }
if (uri.len) { if (uri.len) {
if (uri.data[0] == '@') {
ngx_http_named_location(r, &uri);
} else {
ngx_str_null(&args);
flags = NGX_HTTP_LOG_UNSAFE;
if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
ngx_http_internal_redirect(r, &uri, &args); ngx_http_internal_redirect(r, &uri, &args);
}
ngx_http_finalize_request(r, NGX_DONE); ngx_http_finalize_request(r, NGX_DONE);
return; return;
} }
@@ -299,6 +316,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
ngx_int_t rc; ngx_int_t rc;
ngx_str_t value; ngx_str_t value;
ngx_uint_t saved;
ngx_http_perl_ctx_t *ctx; ngx_http_perl_ctx_t *ctx;
ngx_http_perl_main_conf_t *pmcf; ngx_http_perl_main_conf_t *pmcf;
@@ -314,8 +332,13 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
} }
ngx_http_set_ctx(r, ctx, ngx_http_perl_module); ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
ctx->request = r;
} }
saved = ctx->variable;
ctx->variable = 1;
pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
value.data = NULL; value.data = NULL;
@@ -326,7 +349,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
PERL_SET_CONTEXT(pmcf->perl); PERL_SET_CONTEXT(pmcf->perl);
PERL_SET_INTERP(pmcf->perl); PERL_SET_INTERP(pmcf->perl);
rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL, rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, pv->sub, NULL,
&pv->handler, &value); &pv->handler, &value);
} }
@@ -342,6 +365,7 @@ ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
v->not_found = 1; v->not_found = 1;
} }
ctx->variable = saved;
ctx->filename.data = NULL; ctx->filename.data = NULL;
ctx->redirect_uri.len = 0; ctx->redirect_uri.len = 0;
@@ -377,11 +401,14 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
} }
ngx_http_set_ctx(r, ctx, ngx_http_perl_module); ngx_http_set_ctx(r, ctx, ngx_http_perl_module);
ctx->request = r;
} }
pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module);
ctx->ssi = ssi_ctx; ctx->ssi = ssi_ctx;
ctx->header_sent = 1;
handler = params[NGX_HTTP_PERL_SSI_SUB]; handler = params[NGX_HTTP_PERL_SSI_SUB];
handler->data[handler->len] = '\0'; handler->data[handler->len] = '\0';
@@ -435,8 +462,8 @@ ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx,
asv = NULL; asv = NULL;
} }
rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sv, asv,
NULL); handler, NULL);
SvREFCNT_dec(sv); SvREFCNT_dec(sv);
@@ -672,8 +699,9 @@ ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log)
static ngx_int_t static ngx_int_t
ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
SV **args, ngx_str_t *handler, ngx_str_t *rv) ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args,
ngx_str_t *handler, ngx_str_t *rv)
{ {
SV *sv; SV *sv;
int n, status; int n, status;
@@ -687,12 +715,15 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
status = 0; status = 0;
ctx->error = 0;
ctx->status = NGX_OK;
ENTER; ENTER;
SAVETMPS; SAVETMPS;
PUSHMARK(sp); PUSHMARK(sp);
sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx)); sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(ctx))), nginx));
XPUSHs(sv); XPUSHs(sv);
if (args) { if (args) {
@@ -736,6 +767,18 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
FREETMPS; FREETMPS;
LEAVE; LEAVE;
if (ctx->error) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"call_sv: error, %d", ctx->status);
if (ctx->status != NGX_OK) {
return ctx->status;
}
return NGX_ERROR;
}
/* check $@ */ /* check $@ */
if (SvTRUE(ERRSV)) { if (SvTRUE(ERRSV)) {
@@ -750,6 +793,12 @@ ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub,
return NGX_ERROR; return NGX_ERROR;
} }
ctx->redirect_uri.len = 0;
if (ctx->header_sent) {
return NGX_ERROR;
}
return NGX_HTTP_INTERNAL_SERVER_ERROR; return NGX_HTTP_INTERNAL_SERVER_ERROR;
} }
+8 -2
View File
@@ -21,13 +21,19 @@
typedef ngx_http_request_t *nginx; typedef ngx_http_request_t *nginx;
typedef struct { typedef struct {
ngx_http_request_t *request;
ngx_str_t filename; ngx_str_t filename;
ngx_str_t redirect_uri; ngx_str_t redirect_uri;
ngx_str_t redirect_args;
SV *next; SV *next;
ngx_uint_t done; /* unsigned done:1; */ ngx_int_t status;
unsigned done:1;
unsigned error:1;
unsigned variable:1;
unsigned header_sent:1;
ngx_array_t *variables; /* array of ngx_http_perl_var_t */ ngx_array_t *variables; /* array of ngx_http_perl_var_t */
+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;
+114 -30
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);
@@ -493,7 +496,7 @@ static ngx_command_t ngx_http_core_commands[] = {
{ ngx_string("limit_rate"), { ngx_string("limit_rate"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1, |NGX_CONF_TAKE1,
ngx_conf_set_size_slot, ngx_http_set_complex_value_size_slot,
NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, limit_rate), offsetof(ngx_http_core_loc_conf_t, limit_rate),
NULL }, NULL },
@@ -501,7 +504,7 @@ static ngx_command_t ngx_http_core_commands[] = {
{ ngx_string("limit_rate_after"), { ngx_string("limit_rate_after"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1, |NGX_CONF_TAKE1,
ngx_conf_set_size_slot, ngx_http_set_complex_value_size_slot,
NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, limit_rate_after), offsetof(ngx_http_core_loc_conf_t, limit_rate_after),
NULL }, NULL },
@@ -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)
@@ -1295,10 +1373,6 @@ ngx_http_update_location_config(ngx_http_request_t *r)
r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED;
} }
if (r->limit_rate == 0) {
r->limit_rate = clcf->limit_rate;
}
if (clcf->handler) { if (clcf->handler) {
r->content_handler = clcf->handler; r->content_handler = clcf->handler;
} }
@@ -1678,8 +1752,10 @@ ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
ngx_buf_t *b; ngx_buf_t *b;
ngx_chain_t out; ngx_chain_t out;
if (ngx_http_discard_request_body(r) != NGX_OK) { rc = ngx_http_discard_request_body(r);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
if (rc != NGX_OK) {
return rc;
} }
r->headers_out.status = status; r->headers_out.status = status;
@@ -1859,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;
} }
@@ -2682,11 +2759,15 @@ 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;
found = 0;
do {
if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) { if (ngx_cidr_match(addr->sockaddr, proxies) != NGX_OK) {
return NGX_DECLINED; return found ? NGX_DONE : NGX_DECLINED;
} }
for (p = xff + xfflen - 1; p > xff; p--, xfflen--) { for (p = xff + xfflen - 1; p > xff; p--, xfflen--) {
@@ -2702,23 +2783,17 @@ ngx_http_get_forwarded_addr_internal(ngx_http_request_t *r, ngx_addr_t *addr,
} }
} }
if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff)) != NGX_OK) { if (ngx_parse_addr_port(r->pool, &paddr, p, xfflen - (p - xff))
return NGX_DECLINED; != NGX_OK)
{
return found ? NGX_DONE : NGX_DECLINED;
} }
*addr = paddr; *addr = paddr;
found = 1;
xfflen = p - 1 - xff;
if (recursive && p > xff) { } while (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 */
return rc;
}
return NGX_OK; return NGX_OK;
} }
@@ -3401,6 +3476,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
* clcf->exact_match = 0; * clcf->exact_match = 0;
* clcf->auto_redirect = 0; * clcf->auto_redirect = 0;
* clcf->alias = 0; * clcf->alias = 0;
* clcf->limit_rate = NULL;
* clcf->limit_rate_after = NULL;
* clcf->gzip_proxied = 0; * clcf->gzip_proxied = 0;
* clcf->keepalive_disable = 0; * clcf->keepalive_disable = 0;
*/ */
@@ -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;
@@ -3433,8 +3511,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_timeout = NGX_CONF_UNSET_MSEC;
clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->send_lowat = NGX_CONF_UNSET_SIZE;
clcf->postpone_output = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE;
clcf->limit_rate = NGX_CONF_UNSET_SIZE;
clcf->limit_rate_after = NGX_CONF_UNSET_SIZE;
clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC;
clcf->keepalive_header = NGX_CONF_UNSET; clcf->keepalive_header = NGX_CONF_UNSET;
clcf->keepalive_requests = NGX_CONF_UNSET_UINT; clcf->keepalive_requests = NGX_CONF_UNSET_UINT;
@@ -3628,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,
@@ -3665,9 +3742,15 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0);
ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
1460); 1460);
ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, if (conf->limit_rate == NULL) {
0); conf->limit_rate = prev->limit_rate;
}
if (conf->limit_rate_after == NULL) {
conf->limit_rate_after = prev->limit_rate_after;
}
ngx_conf_merge_msec_value(conf->keepalive_timeout, ngx_conf_merge_msec_value(conf->keepalive_timeout,
prev->keepalive_timeout, 75000); prev->keepalive_timeout, 75000);
ngx_conf_merge_sec_value(conf->keepalive_header, ngx_conf_merge_sec_value(conf->keepalive_header,
@@ -4702,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;
} }
} }
+4 -2
View File
@@ -349,19 +349,21 @@ struct ngx_http_core_loc_conf_s {
size_t client_body_buffer_size; /* client_body_buffer_size */ size_t client_body_buffer_size; /* client_body_buffer_size */
size_t send_lowat; /* send_lowat */ size_t send_lowat; /* send_lowat */
size_t postpone_output; /* postpone_output */ size_t postpone_output; /* postpone_output */
size_t limit_rate; /* limit_rate */
size_t limit_rate_after; /* limit_rate_after */
size_t sendfile_max_chunk; /* sendfile_max_chunk */ size_t sendfile_max_chunk; /* sendfile_max_chunk */
size_t read_ahead; /* read_ahead */ size_t read_ahead; /* read_ahead */
size_t subrequest_output_buffer_size; size_t subrequest_output_buffer_size;
/* subrequest_output_buffer_size */ /* subrequest_output_buffer_size */
ngx_http_complex_value_t *limit_rate; /* limit_rate */
ngx_http_complex_value_t *limit_rate_after; /* limit_rate_after */
ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t client_body_timeout; /* client_body_timeout */
ngx_msec_t send_timeout; /* send_timeout */ ngx_msec_t send_timeout; /* send_timeout */
ngx_msec_t keepalive_timeout; /* keepalive_timeout */ ngx_msec_t keepalive_timeout; /* keepalive_timeout */
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 */
+39 -2
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,9 +1988,21 @@ 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) {
if (!cache->min_free) {
break; 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);
if (wait > 0) { if (wait > 0) {
@@ -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);
+44 -7
View File
@@ -912,6 +912,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
i = 1; i = 1;
} else { } else {
hash = 0;
i = 0;
r->invalid_header = 1; r->invalid_header = 1;
} }
@@ -922,6 +924,8 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
return NGX_HTTP_PARSE_INVALID_HEADER; return NGX_HTTP_PARSE_INVALID_HEADER;
} }
hash = 0;
i = 0;
r->invalid_header = 1; r->invalid_header = 1;
break; break;
@@ -1437,9 +1441,11 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
state = sw_quoted; state = sw_quoted;
break; break;
case '?': case '?':
u--;
r->args_start = p; r->args_start = p;
goto args; goto args;
case '#': case '#':
u--;
goto done; goto done;
case '+': case '+':
r->plus_in_uri = 1; r->plus_in_uri = 1;
@@ -1467,8 +1473,9 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
case '\\': case '\\':
#endif #endif
case '/': case '/':
state = sw_slash; case '?':
u -= 5; case '#':
u -= 4;
for ( ;; ) { for ( ;; ) {
if (u < r->uri.data) { if (u < r->uri.data) {
return NGX_HTTP_PARSE_INVALID_REQUEST; return NGX_HTTP_PARSE_INVALID_REQUEST;
@@ -1479,16 +1486,19 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
} }
u--; u--;
} }
if (ch == '?') {
r->args_start = p;
goto args;
}
if (ch == '#') {
goto done;
}
state = sw_slash;
break; break;
case '%': case '%':
quoted_state = state; quoted_state = state;
state = sw_quoted; state = sw_quoted;
break; break;
case '?':
r->args_start = p;
goto args;
case '#':
goto done;
case '+': case '+':
r->plus_in_uri = 1; r->plus_in_uri = 1;
/* fall through */ /* fall through */
@@ -1561,6 +1571,30 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
} }
} }
if (state == sw_quoted || state == sw_quoted_second) {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
if (state == sw_dot) {
u--;
} else if (state == sw_dot_dot) {
u -= 4;
for ( ;; ) {
if (u < r->uri.data) {
return NGX_HTTP_PARSE_INVALID_REQUEST;
}
if (*u == '/') {
u++;
break;
}
u--;
}
}
done: done:
r->uri.len = u - r->uri.data; r->uri.len = u - r->uri.data;
@@ -2268,6 +2302,9 @@ ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
break; break;
case LF: case LF:
state = sw_chunk_start; state = sw_chunk_start;
break;
default:
goto invalid;
} }
break; break;
+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");
+6 -3
View File
@@ -510,10 +510,13 @@ 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_set:1; unsigned limit_req_status:3;
unsigned limit_rate_set:1;
unsigned limit_rate_after_set:1;
#if 0 #if 0
unsigned cacheable:1; unsigned cacheable:1;
+135 -38
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,21 +284,6 @@ 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) {
/* 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;
}
} else {
/* update chains */ /* update chains */
rc = ngx_http_request_body_filter(r, NULL); rc = ngx_http_request_body_filter(r, NULL);
@@ -304,7 +291,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
if (rc != NGX_OK) { if (rc != NGX_OK) {
return rc; return rc;
} }
}
if (rb->busy != NULL) { if (rb->busy != NULL) {
if (r->request_body_no_buffering) { if (r->request_body_no_buffering) {
@@ -355,7 +341,6 @@ 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;
@@ -366,7 +351,6 @@ ngx_http_do_read_client_request_body(ngx_http_request_t *r)
if (rc != NGX_OK) { if (rc != NGX_OK) {
return rc; return rc;
} }
}
if (rb->rest == 0) { if (rb->rest == 0) {
break; break;
@@ -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,6 +759,14 @@ 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;
} }
@@ -714,6 +776,7 @@ 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;
} }
+69 -1
View File
@@ -104,6 +104,37 @@ ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val,
} }
size_t
ngx_http_complex_value_size(ngx_http_request_t *r,
ngx_http_complex_value_t *val, size_t default_value)
{
size_t size;
ngx_str_t value;
if (val == NULL) {
return default_value;
}
if (val->lengths == NULL) {
return val->u.size;
}
if (ngx_http_complex_value(r, val, &value) != NGX_OK) {
return default_value;
}
size = ngx_parse_size(&value);
if (size == (size_t) NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid size \"%V\"", &value);
return default_value;
}
return size;
}
ngx_int_t ngx_int_t
ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv)
{ {
@@ -244,6 +275,36 @@ ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
} }
char *
ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
char *p = conf;
char *rv;
ngx_http_complex_value_t *cv;
rv = ngx_http_set_complex_value_slot(cf, cmd, conf);
if (rv != NGX_CONF_OK) {
return rv;
}
cv = *(ngx_http_complex_value_t **) (p + cmd->offset);
if (cv->lengths) {
return NGX_CONF_OK;
}
cv->u.size = ngx_parse_size(&cv->value);
if (cv->u.size == (size_t) NGX_ERROR) {
return "invalid value";
}
return NGX_CONF_OK;
}
ngx_int_t ngx_int_t
ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
{ {
@@ -1409,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;
} }
+8
View File
@@ -68,6 +68,10 @@ typedef struct {
ngx_uint_t *flushes; ngx_uint_t *flushes;
void *lengths; void *lengths;
void *values; void *values;
union {
size_t size;
} u;
} ngx_http_complex_value_t; } ngx_http_complex_value_t;
@@ -207,9 +211,13 @@ void ngx_http_script_flush_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val); ngx_http_complex_value_t *val);
ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_int_t ngx_http_complex_value(ngx_http_request_t *r,
ngx_http_complex_value_t *val, ngx_str_t *value); ngx_http_complex_value_t *val, ngx_str_t *value);
size_t ngx_http_complex_value_size(ngx_http_request_t *r,
ngx_http_complex_value_t *val, size_t default_value);
ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv);
char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf); void *conf);
char *ngx_http_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r,
+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) {
+52 -18
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);
@@ -597,10 +594,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
u->cache_status = NGX_HTTP_CACHE_MISS; u->cache_status = NGX_HTTP_CACHE_MISS;
u->request_sent = 1; u->request_sent = 1;
} }
if (ngx_http_upstream_cache_background_update(r, u) != NGX_OK) {
rc = NGX_ERROR;
}
} }
if (rc != NGX_DECLINED) { if (rc != NGX_DECLINED) {
@@ -902,9 +895,14 @@ ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
|| c->stale_updating) && !r->background || c->stale_updating) && !r->background
&& u->conf->cache_background_update) && u->conf->cache_background_update)
{ {
if (ngx_http_upstream_cache_background_update(r, u) == NGX_OK) {
r->cache->background = 1; r->cache->background = 1;
u->cache_status = rc; u->cache_status = rc;
rc = NGX_OK; rc = NGX_OK;
} else {
rc = NGX_ERROR;
}
} }
break; break;
@@ -1106,10 +1104,6 @@ ngx_http_upstream_cache_background_update(ngx_http_request_t *r,
{ {
ngx_http_request_t *sr; ngx_http_request_t *sr;
if (!r->cached || !r->cache->background) {
return NGX_OK;
}
if (r == r->main) { if (r == r->main) {
r->preserve_body = 1; r->preserve_body = 1;
} }
@@ -1922,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;
@@ -2478,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;
@@ -2505,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)
@@ -2979,6 +2976,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_http_upstream_process_non_buffered_downstream; ngx_http_upstream_process_non_buffered_downstream;
r->limit_rate = 0; r->limit_rate = 0;
r->limit_rate_set = 1;
if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) { if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR); ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
@@ -3336,6 +3334,7 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
size_t size; size_t size;
ssize_t n; ssize_t n;
ngx_buf_t *b; ngx_buf_t *b;
ngx_uint_t flags;
ngx_connection_t *c, *downstream, *upstream, *dst, *src; ngx_connection_t *c, *downstream, *upstream, *dst, *src;
ngx_http_upstream_t *u; ngx_http_upstream_t *u;
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
@@ -3474,7 +3473,14 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
ngx_del_timer(upstream->write); ngx_del_timer(upstream->write);
} }
if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { if (upstream->read->eof || upstream->read->error) {
flags = NGX_CLOSE_EVENT;
} else {
flags = 0;
}
if (ngx_handle_read_event(upstream->read, flags) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR); ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return; return;
} }
@@ -3493,7 +3499,14 @@ ngx_http_upstream_process_upgraded(ngx_http_request_t *r,
return; return;
} }
if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { if (downstream->read->eof || downstream->read->error) {
flags = NGX_CLOSE_EVENT;
} else {
flags = 0;
}
if (ngx_handle_read_event(downstream->read, flags) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR); ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return; return;
} }
@@ -3565,6 +3578,7 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
ssize_t n; ssize_t n;
ngx_buf_t *b; ngx_buf_t *b;
ngx_int_t rc; ngx_int_t rc;
ngx_uint_t flags;
ngx_connection_t *downstream, *upstream; ngx_connection_t *downstream, *upstream;
ngx_http_upstream_t *u; ngx_http_upstream_t *u;
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
@@ -3611,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;
@@ -3668,7 +3682,14 @@ ngx_http_upstream_process_non_buffered_request(ngx_http_request_t *r,
ngx_del_timer(downstream->write); ngx_del_timer(downstream->write);
} }
if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { if (upstream->read->eof || upstream->read->error) {
flags = NGX_CLOSE_EVENT;
} else {
flags = 0;
}
if (ngx_handle_read_event(upstream->read, flags) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR); ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return; return;
} }
@@ -3682,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;
@@ -3725,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;
@@ -4806,6 +4839,7 @@ ngx_http_upstream_process_limit_rate(ngx_http_request_t *r, ngx_table_elt_t *h,
if (n != NGX_ERROR) { if (n != NGX_ERROR) {
r->limit_rate = (size_t) n; r->limit_rate = (size_t) n;
r->limit_rate_set = 1;
} }
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 -4
View File
@@ -669,10 +669,7 @@ ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
ngx_http_upstream_rr_peer_t *peer; ngx_http_upstream_rr_peer_t *peer;
#if (NGX_HTTP_UPSTREAM_ZONE) #if (NGX_HTTP_UPSTREAM_ZONE)
int len; int len;
#if OPENSSL_VERSION_NUMBER >= 0x0090707fL const u_char *p;
const
#endif
u_char *p;
ngx_http_upstream_rr_peers_t *peers; ngx_http_upstream_rr_peers_t *peers;
u_char buf[NGX_SSL_MAX_SESSION_SIZE]; u_char buf[NGX_SSL_MAX_SESSION_SIZE];
#endif #endif
+60 -35
View File
@@ -22,8 +22,6 @@ static void ngx_http_variable_request_set(ngx_http_request_t *r,
#endif #endif
static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data); ngx_http_variable_value_t *v, uintptr_t data);
static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data); ngx_http_variable_value_t *v, uintptr_t data);
@@ -124,6 +122,8 @@ static ngx_int_t ngx_http_variable_sent_keep_alive(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data); ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r, static ngx_int_t ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data); ngx_http_variable_value_t *v, uintptr_t data);
static void ngx_http_variable_set_limit_rate(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r, static ngx_int_t ngx_http_variable_connection(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data); ngx_http_variable_value_t *v, uintptr_t data);
@@ -199,10 +199,20 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 }, { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
{ ngx_string("proxy_protocol_addr"), NULL, { ngx_string("proxy_protocol_addr"), NULL,
ngx_http_variable_proxy_protocol_addr, 0, 0, 0 }, ngx_http_variable_proxy_protocol_addr,
offsetof(ngx_proxy_protocol_t, src_addr), 0, 0 },
{ ngx_string("proxy_protocol_port"), NULL, { ngx_string("proxy_protocol_port"), NULL,
ngx_http_variable_proxy_protocol_port, 0, 0, 0 }, ngx_http_variable_proxy_protocol_port,
offsetof(ngx_proxy_protocol_t, src_port), 0, 0 },
{ ngx_string("proxy_protocol_server_addr"), NULL,
ngx_http_variable_proxy_protocol_addr,
offsetof(ngx_proxy_protocol_t, dst_addr), 0, 0 },
{ ngx_string("proxy_protocol_server_port"), NULL,
ngx_http_variable_proxy_protocol_port,
offsetof(ngx_proxy_protocol_t, dst_port), 0, 0 },
{ ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 }, { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
@@ -321,7 +331,7 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("sent_http_link"), NULL, ngx_http_variable_headers, { ngx_string("sent_http_link"), NULL, ngx_http_variable_headers,
offsetof(ngx_http_request_t, headers_out.link), 0, 0 }, offsetof(ngx_http_request_t, headers_out.link), 0, 0 },
{ ngx_string("limit_rate"), ngx_http_variable_request_set_size, { ngx_string("limit_rate"), ngx_http_variable_set_limit_rate,
ngx_http_variable_request_get_size, ngx_http_variable_request_get_size,
offsetof(ngx_http_request_t, limit_rate), offsetof(ngx_http_request_t, limit_rate),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
@@ -788,32 +798,6 @@ ngx_http_variable_request_get_size(ngx_http_request_t *r,
} }
static void
ngx_http_variable_request_set_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ssize_t s, *sp;
ngx_str_t val;
val.len = v->len;
val.data = v->data;
s = ngx_parse_size(&val);
if (s == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid size \"%V\"", &val);
return;
}
sp = (ssize_t *) ((char *) r + data);
*sp = s;
return;
}
static ngx_int_t static ngx_int_t
ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data) uintptr_t data)
@@ -1091,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;
} }
@@ -1319,11 +1303,22 @@ static ngx_int_t
ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r, ngx_http_variable_proxy_protocol_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data) ngx_http_variable_value_t *v, uintptr_t data)
{ {
v->len = r->connection->proxy_protocol_addr.len; ngx_str_t *addr;
ngx_proxy_protocol_t *pp;
pp = r->connection->proxy_protocol;
if (pp == NULL) {
v->not_found = 1;
return NGX_OK;
}
addr = (ngx_str_t *) ((char *) pp + data);
v->len = addr->len;
v->valid = 1; v->valid = 1;
v->no_cacheable = 0; v->no_cacheable = 0;
v->not_found = 0; v->not_found = 0;
v->data = r->connection->proxy_protocol_addr.data; v->data = addr->data;
return NGX_OK; return NGX_OK;
} }
@@ -1334,6 +1329,13 @@ ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data) ngx_http_variable_value_t *v, uintptr_t data)
{ {
ngx_uint_t port; ngx_uint_t port;
ngx_proxy_protocol_t *pp;
pp = r->connection->proxy_protocol;
if (pp == NULL) {
v->not_found = 1;
return NGX_OK;
}
v->len = 0; v->len = 0;
v->valid = 1; v->valid = 1;
@@ -1345,7 +1347,7 @@ ngx_http_variable_proxy_protocol_port(ngx_http_request_t *r,
return NGX_ERROR; return NGX_ERROR;
} }
port = r->connection->proxy_protocol_port; port = *(in_port_t *) ((char *) pp + data);
if (port > 0 && port < 65536) { if (port > 0 && port < 65536) {
v->len = ngx_sprintf(v->data, "%ui", port) - v->data; v->len = ngx_sprintf(v->data, "%ui", port) - v->data;
@@ -1993,6 +1995,29 @@ ngx_http_variable_sent_transfer_encoding(ngx_http_request_t *r,
} }
static void
ngx_http_variable_set_limit_rate(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
ssize_t s;
ngx_str_t val;
val.len = v->len;
val.data = v->data;
s = ngx_parse_size(&val);
if (s == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid $limit_rate \"%V\"", &val);
return;
}
r->limit_rate = s;
r->limit_rate_set = 1;
}
static ngx_int_t static ngx_int_t
ngx_http_variable_request_completion(ngx_http_request_t *r, ngx_http_variable_request_completion(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data) ngx_http_variable_value_t *v, uintptr_t data)
+10 -2
View File
@@ -250,9 +250,17 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
return NGX_ERROR; return NGX_ERROR;
} }
if (!r->limit_rate_set) {
r->limit_rate = ngx_http_complex_value_size(r, clcf->limit_rate, 0);
r->limit_rate_set = 1;
}
if (r->limit_rate) { if (r->limit_rate) {
if (r->limit_rate_after == 0) {
r->limit_rate_after = clcf->limit_rate_after; if (!r->limit_rate_after_set) {
r->limit_rate_after = ngx_http_complex_value_size(r,
clcf->limit_rate_after, 0);
r->limit_rate_after_set = 1;
} }
limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1)
+214 -110
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,
@@ -275,6 +278,7 @@ ngx_http_v2_init(ngx_event_t *rev)
h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module); h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
h2c->concurrent_pushes = h2scf->concurrent_pushes; h2c->concurrent_pushes = h2scf->concurrent_pushes;
h2c->priority_limit = h2scf->concurrent_streams;
h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
if (h2c->pool == NULL) { if (h2c->pool == NULL) {
@@ -355,6 +359,11 @@ ngx_http_v2_read_handler(ngx_event_t *rev)
if (c->close) { if (c->close) {
c->close = 0; c->close = 0;
if (c->error) {
ngx_http_v2_finalize_connection(h2c, 0);
return;
}
if (!h2c->goaway) { if (!h2c->goaway) {
h2c->goaway = 1; h2c->goaway = 1;
@@ -420,6 +429,14 @@ ngx_http_v2_read_handler(ngx_event_t *rev)
} while (p != end); } while (p != end);
h2c->total_bytes += n;
if (h2c->total_bytes / 8 > h2c->payload_bytes + 1048576) {
ngx_log_error(NGX_LOG_INFO, c->log, 0, "http2 flood detected");
ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR);
return;
}
} while (rev->ready); } while (rev->ready);
if (ngx_handle_read_event(rev, 0) != NGX_OK) { if (ngx_handle_read_event(rev, 0) != NGX_OK) {
@@ -460,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;
} }
@@ -506,13 +524,12 @@ ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c)
ngx_http_core_loc_conf_t *clcf; ngx_http_core_loc_conf_t *clcf;
c = h2c->connection; c = h2c->connection;
wev = c->write;
if (c->error) { if (c->error) {
return NGX_ERROR; goto error;
} }
wev = c->write;
if (!wev->ready) { if (!wev->ready) {
return NGX_AGAIN; return NGX_AGAIN;
} }
@@ -649,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;
} }
@@ -687,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)
@@ -719,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);
} }
@@ -742,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);
} }
@@ -948,6 +1070,15 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
return ngx_http_v2_state_skip_padded(h2c, pos, end); return ngx_http_v2_state_skip_padded(h2c, pos, end);
} }
r = stream->request;
if (r->reading_body && !r->request_body_no_buffering) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"skipping http2 DATA frame");
return ngx_http_v2_state_skip_padded(h2c, pos, end);
}
size = end - pos; size = end - pos;
if (size >= h2c->state.length) { if (size >= h2c->state.length) {
@@ -955,7 +1086,7 @@ ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
} }
r = stream->request; h2c->payload_bytes += size;
if (r->request_body) { if (r->request_body) {
rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed); rc = ngx_http_v2_process_request_body(r, pos, size, stream->in_closed);
@@ -1101,20 +1232,19 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *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);
} }
h2c->last_sid = h2c->state.sid;
h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
if (h2c->state.pool == NULL) {
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
}
if (depend == h2c->state.sid) { if (depend == h2c->state.sid) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent HEADERS frame for stream %ui " "client sent HEADERS frame for stream %ui "
"with incorrect dependency", h2c->state.sid); "with incorrect dependency", h2c->state.sid);
status = NGX_HTTP_V2_PROTOCOL_ERROR; return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
goto rst_stream; }
h2c->last_sid = h2c->state.sid;
h2c->state.pool = ngx_create_pool(1024, h2c->connection->log);
if (h2c->state.pool == NULL) {
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR);
} }
h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx,
@@ -1548,6 +1678,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
header->name.len = h2c->state.field_end - h2c->state.field_start; header->name.len = h2c->state.field_end - h2c->state.field_start;
header->name.data = h2c->state.field_start; header->name.data = h2c->state.field_start;
if (header->name.len == 0) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent zero header name length");
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_PROTOCOL_ERROR);
}
return ngx_http_v2_state_field_len(h2c, pos, end); return ngx_http_v2_state_field_len(h2c, pos, end);
} }
@@ -1691,10 +1829,15 @@ 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) {
if (end - pos > 0) {
h2c->state.handler = ngx_http_v2_state_header_block; h2c->state.handler = ngx_http_v2_state_header_block;
return pos; 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)) {
return ngx_http_v2_handle_continuation(h2c, pos, end, return ngx_http_v2_handle_continuation(h2c, pos, end,
ngx_http_v2_state_header_complete); ngx_http_v2_state_header_complete);
@@ -1798,6 +1941,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
} }
if (--h2c->priority_limit == 0) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent too many PRIORITY frames");
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
}
if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) { if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) {
return ngx_http_v2_state_save(h2c, pos, end, return ngx_http_v2_state_save(h2c, pos, end,
ngx_http_v2_state_priority); ngx_http_v2_state_priority);
@@ -1828,28 +1978,7 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
"client sent PRIORITY frame for stream %ui " "client sent PRIORITY frame for stream %ui "
"with incorrect dependency", h2c->state.sid); "with incorrect dependency", h2c->state.sid);
node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0); return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
if (node && node->stream) {
if (ngx_http_v2_terminate_stream(h2c, node->stream,
NGX_HTTP_V2_PROTOCOL_ERROR)
== NGX_ERROR)
{
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_INTERNAL_ERROR);
}
} else {
if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
NGX_HTTP_V2_PROTOCOL_ERROR)
== NGX_ERROR)
{
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_INTERNAL_ERROR);
}
}
return ngx_http_v2_state_complete(h2c, pos, end);
} }
node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1);
@@ -2240,41 +2369,11 @@ ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos,
h2c->state.sid, window); h2c->state.sid, window);
if (window == 0) { if (window == 0) {
if (h2c->state.sid == 0) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent WINDOW_UPDATE frame " "client sent WINDOW_UPDATE frame "
"with incorrect window increment 0"); "with incorrect window increment 0");
return ngx_http_v2_connection_error(h2c, return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
NGX_HTTP_V2_PROTOCOL_ERROR);
}
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent WINDOW_UPDATE frame for stream %ui "
"with incorrect window increment 0", h2c->state.sid);
node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
if (node && node->stream) {
if (ngx_http_v2_terminate_stream(h2c, node->stream,
NGX_HTTP_V2_PROTOCOL_ERROR)
== NGX_ERROR)
{
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_INTERNAL_ERROR);
}
} else {
if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
NGX_HTTP_V2_PROTOCOL_ERROR)
== NGX_ERROR)
{
return ngx_http_v2_connection_error(h2c,
NGX_HTTP_V2_INTERNAL_ERROR);
}
}
return ngx_http_v2_state_complete(h2c, pos, end);
} }
if (h2c->state.sid) { if (h2c->state.sid) {
@@ -2490,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;
@@ -2948,9 +3043,9 @@ ngx_http_v2_get_frame(ngx_http_v2_connection_t *h2c, size_t length,
"requested control frame is too large: %uz", length); "requested control frame is too large: %uz", length);
return NULL; return NULL;
} }
#endif
frame->length = length; frame->length = length;
#endif
buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type); buf->last = ngx_http_v2_write_len_and_type(buf->pos, length, type);
@@ -2977,6 +3072,8 @@ ngx_http_v2_frame_handler(ngx_http_v2_connection_t *h2c,
frame->next = h2c->free_frames; frame->next = h2c->free_frames;
h2c->free_frames = frame; h2c->free_frames = frame;
h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
return NGX_OK; return NGX_OK;
} }
@@ -3122,6 +3219,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push)
h2c->processing++; h2c->processing++;
} }
h2c->priority_limit += h2scf->concurrent_streams;
return stream; return stream;
} }
@@ -3259,10 +3358,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
ngx_uint_t i; ngx_uint_t i;
ngx_http_core_srv_conf_t *cscf; ngx_http_core_srv_conf_t *cscf;
if (header->name.len == 0) {
return NGX_ERROR;
}
r->invalid_header = 0; r->invalid_header = 0;
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
@@ -3765,6 +3860,7 @@ static void
ngx_http_v2_run_request(ngx_http_request_t *r) ngx_http_v2_run_request(ngx_http_request_t *r)
{ {
ngx_connection_t *fc; ngx_connection_t *fc;
ngx_http_v2_connection_t *h2c;
fc = r->connection; fc = r->connection;
@@ -3796,6 +3892,10 @@ ngx_http_v2_run_request(ngx_http_request_t *r)
r->headers_in.chunked = 1; r->headers_in.chunked = 1;
} }
h2c = r->stream->connection;
h2c->payload_bytes += r->request_length;
ngx_http_process_request(r); ngx_http_process_request(r);
failed: failed:
@@ -4308,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;
} }
@@ -4325,33 +4426,11 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
} }
} else if (!stream->in_closed) { } else if (!stream->in_closed) {
#if 0
if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR) if (ngx_http_v2_send_rst_stream(h2c, node->id, NGX_HTTP_V2_NO_ERROR)
!= NGX_OK) != NGX_OK)
{ {
h2c->connection->error = 1; h2c->connection->error = 1;
} }
#else
/*
* At the time of writing at least the latest versions of Chrome
* do not properly handle RST_STREAM with NO_ERROR status.
*
* See: https://bugs.chromium.org/p/chromium/issues/detail?id=603182
*
* As a workaround, the stream window is maximized before closing
* the stream. This allows a client to send up to 2 GB of data
* before getting blocked on flow control.
*/
if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW
&& ngx_http_v2_send_window_update(h2c, node->id,
NGX_HTTP_V2_MAX_WINDOW
- stream->recv_window)
!= NGX_OK)
{
h2c->connection->error = 1;
}
#endif
} }
} }
@@ -4375,6 +4454,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
*/ */
pool = stream->pool; pool = stream->pool;
h2c->frames -= stream->frames;
ngx_http_free_request(stream->request, rc); ngx_http_free_request(stream->request, rc);
if (pool != h2c->state.pool) { if (pool != h2c->state.pool) {
@@ -4451,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)
{ {
@@ -4564,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;
@@ -4621,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;
} }
done:
if (c->error) {
ngx_http_close_connection(c); ngx_http_close_connection(c);
return;
}
ngx_http_v2_lingering_close(h2c);
} }
+8
View File
@@ -167,9 +167,13 @@ struct ngx_http_v2_connection_s {
ngx_connection_t *connection; ngx_connection_t *connection;
ngx_http_connection_t *http_connection; ngx_http_connection_t *http_connection;
off_t total_bytes;
off_t payload_bytes;
ngx_uint_t processing; ngx_uint_t processing;
ngx_uint_t frames; ngx_uint_t frames;
ngx_uint_t idle; ngx_uint_t idle;
ngx_uint_t priority_limit;
ngx_uint_t pushing; ngx_uint_t pushing;
ngx_uint_t concurrent_pushes; ngx_uint_t concurrent_pushes;
@@ -203,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;
@@ -247,6 +253,8 @@ struct ngx_http_v2_stream_s {
ngx_buf_t *preread; ngx_buf_t *preread;
ngx_uint_t frames;
ngx_http_v2_out_frame_t *free_frames; ngx_http_v2_out_frame_t *free_frames;
ngx_chain_t *free_frame_headers; ngx_chain_t *free_frame_headers;
ngx_chain_t *free_bufs; ngx_chain_t *free_bufs;
+30 -1
View File
@@ -1420,6 +1420,12 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
if (in == NULL || stream->out_closed) { if (in == NULL || stream->out_closed) {
if (size) {
ngx_log_error(NGX_LOG_ERR, fc->log, 0,
"output on closed stream");
return NGX_CHAIN_ERROR;
}
if (stream->queued) { if (stream->queued) {
fc->write->active = 1; fc->write->active = 1;
fc->write->ready = 0; fc->write->ready = 0;
@@ -1643,18 +1649,30 @@ ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream,
ngx_buf_t *buf; ngx_buf_t *buf;
ngx_chain_t *cl; ngx_chain_t *cl;
ngx_http_v2_out_frame_t *frame; ngx_http_v2_out_frame_t *frame;
ngx_http_v2_connection_t *h2c;
frame = stream->free_frames; frame = stream->free_frames;
h2c = stream->connection;
if (frame) { if (frame) {
stream->free_frames = frame->next; stream->free_frames = frame->next;
} else { } else if (h2c->frames < 10000) {
frame = ngx_palloc(stream->request->pool, frame = ngx_palloc(stream->request->pool,
sizeof(ngx_http_v2_out_frame_t)); sizeof(ngx_http_v2_out_frame_t));
if (frame == NULL) { if (frame == NULL) {
return NULL; return NULL;
} }
stream->frames++;
h2c->frames++;
} else {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"http2 flood detected");
h2c->connection->error = 1;
return NULL;
} }
flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0; flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0;
@@ -1835,6 +1853,8 @@ ngx_http_v2_headers_frame_handler(ngx_http_v2_connection_t *h2c,
stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
+ frame->length; + frame->length;
h2c->payload_bytes += frame->length;
ngx_http_v2_handle_frame(stream, frame); ngx_http_v2_handle_frame(stream, frame);
ngx_http_v2_handle_stream(h2c, stream); ngx_http_v2_handle_stream(h2c, stream);
@@ -1889,6 +1909,8 @@ ngx_http_v2_push_frame_handler(ngx_http_v2_connection_t *h2c,
stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE
+ frame->length; + frame->length;
h2c->payload_bytes += frame->length;
ngx_http_v2_handle_frame(stream, frame); ngx_http_v2_handle_frame(stream, frame);
ngx_http_v2_handle_stream(h2c, stream); ngx_http_v2_handle_stream(h2c, stream);
@@ -1982,6 +2004,8 @@ done:
stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE; stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE;
h2c->payload_bytes += frame->length;
ngx_http_v2_handle_frame(stream, frame); ngx_http_v2_handle_frame(stream, frame);
ngx_http_v2_handle_stream(h2c, stream); ngx_http_v2_handle_stream(h2c, stream);
@@ -1995,11 +2019,16 @@ ngx_http_v2_handle_frame(ngx_http_v2_stream_t *stream,
ngx_http_v2_out_frame_t *frame) ngx_http_v2_out_frame_t *frame)
{ {
ngx_http_request_t *r; ngx_http_request_t *r;
ngx_http_v2_connection_t *h2c;
r = stream->request; r = stream->request;
r->connection->sent += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length; r->connection->sent += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
h2c = stream->connection;
h2c->total_bytes += NGX_HTTP_V2_FRAME_HEADER_SIZE + frame->length;
if (frame->fin) { if (frame->fin) {
stream->out_closed = 1; stream->out_closed = 1;
} }
+43
View File
@@ -15,6 +15,7 @@
static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
static void ngx_mail_smtp_resolve_name(ngx_event_t *rev); static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
static void ngx_mail_smtp_block_reading(ngx_event_t *rev);
static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s,
@@ -88,6 +89,9 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
ctx->data = s; ctx->data = s;
ctx->timeout = cscf->resolver_timeout; ctx->timeout = cscf->resolver_timeout;
s->resolver_ctx = ctx;
c->read->handler = ngx_mail_smtp_block_reading;
if (ngx_resolve_addr(ctx) != NGX_OK) { if (ngx_resolve_addr(ctx) != NGX_OK) {
ngx_mail_close_connection(c); ngx_mail_close_connection(c);
} }
@@ -169,6 +173,9 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)
ctx->data = s; ctx->data = s;
ctx->timeout = cscf->resolver_timeout; ctx->timeout = cscf->resolver_timeout;
s->resolver_ctx = ctx;
c->read->handler = ngx_mail_smtp_block_reading;
if (ngx_resolve_name(ctx) != NGX_OK) { if (ngx_resolve_name(ctx) != NGX_OK) {
ngx_mail_close_connection(c); ngx_mail_close_connection(c);
} }
@@ -238,6 +245,38 @@ found:
} }
static void
ngx_mail_smtp_block_reading(ngx_event_t *rev)
{
ngx_connection_t *c;
ngx_mail_session_t *s;
ngx_resolver_ctx_t *ctx;
c = rev->data;
s = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp reading blocked");
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
if (s->resolver_ctx) {
ctx = s->resolver_ctx;
if (ctx->handler == ngx_mail_smtp_resolve_addr_handler) {
ngx_resolve_addr_done(ctx);
} else if (ctx->handler == ngx_mail_smtp_resolve_name_handler) {
ngx_resolve_name_done(ctx);
}
s->resolver_ctx = NULL;
}
ngx_mail_close_connection(c);
}
}
static void static void
ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
{ {
@@ -258,6 +297,10 @@ ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c)
ngx_mail_close_connection(c); ngx_mail_close_connection(c);
} }
if (c->read->ready) {
ngx_post_event(c->read, &ngx_posted_events);
}
if (sscf->greeting_delay) { if (sscf->greeting_delay) {
c->read->handler = ngx_mail_smtp_invalid_pipelining; c->read->handler = ngx_mail_smtp_invalid_pipelining;
return; return;
+1 -1
View File
@@ -398,7 +398,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->client_certificate.len == 0 && conf->verify != 3) { if (conf->client_certificate.len == 0 && conf->verify != 3) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0, ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"no ssl_client_certificate for ssl_client_verify"); "no ssl_client_certificate for ssl_verify_client");
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
+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

Some files were not shown because too many files have changed in this diff Show More