Merge branch 'nginx' (nginx-1.11.8).
Change-Id: I5bdbcb1d9b3cba7334721307bf21d86536e73cd6
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index ffd9d06..43df105 100644
--- a/.hgtags
+++ b/.hgtags
@@ -406,3 +406,4 @@
5253015a339aaca0a3111473d3e931b6d4752393 release-1.11.5
5e371426b3bcba4312ce08606194b89b758927d1 release-1.11.6
5c8f60faf33ca8926473d2da27b4c3c417bd4630 release-1.11.7
+4591da489a30f790def29bc5987f43409b503cae release-1.11.8
diff --git a/BUILD b/BUILD
index 1d3b91a..2cfb7b5 100644
--- a/BUILD
+++ b/BUILD
@@ -1468,5 +1468,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.11.7",
+ version = "1.11.8",
)
diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf
index dbe2e0a..d316ec7 100644
--- a/auto/lib/openssl/conf
+++ b/auto/lib/openssl/conf
@@ -15,8 +15,16 @@
CORE_INCS="$CORE_INCS $OPENSSL/openssl/include"
CORE_DEPS="$CORE_DEPS $OPENSSL/openssl/include/openssl/ssl.h"
- CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/ssleay32.lib"
- CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libeay32.lib"
+
+ if [ -f $OPENSSL/ms/do_ms.bat ]; then
+ # before OpenSSL 1.1.0
+ CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/ssleay32.lib"
+ CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libeay32.lib"
+ else
+ # OpenSSL 1.1.0+
+ CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libssl.lib"
+ CORE_LIBS="$CORE_LIBS $OPENSSL/openssl/lib/libcrypto.lib"
+ fi
# libeay32.lib requires gdi32.lib
CORE_LIBS="$CORE_LIBS gdi32.lib"
diff --git a/auto/lib/openssl/makefile.msvc b/auto/lib/openssl/makefile.msvc
index fc9e578..5b90dcb 100644
--- a/auto/lib/openssl/makefile.msvc
+++ b/auto/lib/openssl/makefile.msvc
@@ -6,9 +6,16 @@
all:
cd $(OPENSSL)
- perl Configure VC-WIN32 no-shared --prefix=openssl $(OPENSSL_OPT)
+ perl Configure VC-WIN32 no-shared \
+ --prefix="%cd%/openssl" \
+ --openssldir="%cd%/openssl/ssl" \
+ $(OPENSSL_OPT)
- ms\do_ms
-
- $(MAKE) -f ms\nt.mak
- $(MAKE) -f ms\nt.mak install
+ if exist ms\do_ms.bat ( \
+ ms\do_ms \
+ && $(MAKE) -f ms\nt.mak \
+ && $(MAKE) -f ms\nt.mak install \
+ ) else ( \
+ $(MAKE) \
+ && $(MAKE) install_sw \
+ )
diff --git a/auto/lib/perl/make b/auto/lib/perl/make
index 350090c..74e0f3a 100644
--- a/auto/lib/perl/make
+++ b/auto/lib/perl/make
@@ -3,9 +3,6 @@
# Copyright (C) Nginx, Inc.
-v=`grep 'define NGINX_VERSION' src/core/nginx.h | sed -e 's/^.*"\(.*\)".*/\1/'`
-
-
cat << END >> $NGX_MAKEFILE
$NGX_OBJS/src/http/modules/perl/ngx_http_perl_module.o: \\
@@ -27,7 +24,11 @@
src/http/modules/perl/nginx.pm \\
src/http/modules/perl/nginx.xs \\
src/http/modules/perl/typemap
- sed "s/%%VERSION%%/$v/" src/http/modules/perl/nginx.pm > \\
+ grep 'define NGINX_VERSION' src/core/nginx.h \\
+ | sed -e 's/^.*"\(.*\)".*/\1/' > \\
+ $NGX_OBJS/src/http/modules/perl/version
+ sed "s/%%VERSION%%/\`cat $NGX_OBJS/src/http/modules/perl/version\`/" \\
+ src/http/modules/perl/nginx.pm > \\
$NGX_OBJS/src/http/modules/perl/nginx.pm
cp -p src/http/modules/perl/nginx.xs $NGX_OBJS/src/http/modules/perl/
cp -p src/http/modules/perl/typemap $NGX_OBJS/src/http/modules/perl/
diff --git a/build.bzl b/build.bzl
index c3de23b..404bbeb 100644
--- a/build.bzl
+++ b/build.bzl
@@ -668,7 +668,7 @@
name = "nginx_pkgoss",
build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
_PKGOSS_BUILD_FILE_TAIL,
- commit = "4a0aa6d52a93ef2ed0712edc3a67ac345caa9e14", # nginx-1.11.7
+ commit = "9f56e1d4b0141318a00babc933b18d6e85638372", # nginx-1.11.8
remote = "https://nginx.googlesource.com/nginx-pkgoss",
)
diff --git a/contrib/vim/ftplugin/nginx.vim b/contrib/vim/ftplugin/nginx.vim
new file mode 100644
index 0000000..463eea9
--- /dev/null
+++ b/contrib/vim/ftplugin/nginx.vim
@@ -0,0 +1 @@
+setlocal commentstring=#\ %s
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 0a440e4..1f0e2c6 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,113 @@
<change_log title="nginx">
+<changes ver="1.11.8" date="27.12.2016">
+
+<change type="feature">
+<para lang="ru">
+директива absolute_redirect.
+</para>
+<para lang="en">
+the "absolute_redirect" directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+параметр escape директивы log_format.
+</para>
+<para lang="en">
+the "escape" parameter of the "log_format" directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+проверка клиентских SSL-сертификатов в модуле stream.
+</para>
+<para lang="en">
+client SSL certificates verification in the stream module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива ssl_session_ticket_key поддерживает
+шифрование TLS session tickets с помощью AES256
+при использовании с 80-байтными ключами.
+</para>
+<para lang="en">
+the "ssl_session_ticket_key" directive supports
+AES256 encryption of TLS session tickets
+when used with 80-byte keys.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+поддержка vim-commentary в скриптах для vim.<br/>
+Спасибо Armin Grodon.
+</para>
+<para lang="en">
+vim-commentary support in vim scripts.<br/>
+Thanks to Armin Grodon.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+рекурсия при получении значений переменных не ограничивалась.
+</para>
+<para lang="en">
+recursion when evaluating variables was not limited.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в модуле ngx_stream_ssl_preread_module.
+</para>
+<para lang="en">
+in the ngx_stream_ssl_preread_module.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если сервер, описанный в блоке upstream в модуле stream,
+был признан неработающим, то после истечения fail_timeout он
+признавался работающим только после завершения тестового соединения;
+теперь достаточно, чтобы соединение было успешно установлено.
+</para>
+<para lang="en">
+if a server in an upstream in the stream module failed,
+it was considered alive only when a test connection sent
+to it after fail_timeout was closed;
+now a successfully established connection is enough.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx/Windows не собирался с 64-битным Visual Studio.
+</para>
+<para lang="en">
+nginx/Windows could not be built with 64-bit Visual Studio.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+nginx/Windows не собирался с OpenSSL 1.1.0.
+</para>
+<para lang="en">
+nginx/Windows could not be built with OpenSSL 1.1.0.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.11.7" date="13.12.2016">
<change type="change">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index 9ab4193..064fac1 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -4,6 +4,7 @@
NGINX = nginx-$(VER)
TEMP = tmp
+CC = cl
OBJS = objs.msvc8
OPENSSL = openssl-1.0.2j
ZLIB = zlib-1.2.8
@@ -47,7 +48,7 @@
win32:
./auto/configure \
- --with-cc=cl \
+ --with-cc=$(CC) \
--builddir=$(OBJS) \
--with-debug \
--prefix= \
diff --git a/src/core/nginx.h b/src/core/nginx.h
index c8fb05f..3ee7ea8 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1011007
-#define NGINX_VERSION "1.11.7"
+#define nginx_version 1011008
+#define NGINX_VERSION "1.11.8"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index bdfed88..2065f75 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -300,6 +300,10 @@
#endif
if (r->event) {
+ if (r->event->timer_set) {
+ ngx_del_timer(r->event);
+ }
+
ngx_free(r->event);
}
@@ -347,6 +351,10 @@
next = ctx->next;
if (ctx->event) {
+ if (ctx->event->timer_set) {
+ ngx_del_timer(ctx->event);
+ }
+
ngx_resolver_free(r, ctx->event);
}
@@ -772,7 +780,7 @@
#endif
if (rn->nsrvs) {
- for (i = 0; i < rn->nsrvs; i++) {
+ for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
if (rn->u.srvs[i].name.data) {
ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
}
@@ -867,7 +875,7 @@
ngx_add_timer(ctx->event, ctx->timeout);
}
- if (ngx_queue_empty(resend_queue)) {
+ if (ngx_resolver_resend_empty(r)) {
ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
}
@@ -1090,7 +1098,7 @@
ngx_add_timer(ctx->event, ctx->timeout);
}
- if (ngx_queue_empty(resend_queue)) {
+ if (ngx_resolver_resend_empty(r)) {
ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
}
@@ -1548,6 +1556,7 @@
ngx_resolver_resend_empty(ngx_resolver_t *r)
{
return ngx_queue_empty(&r->name_resend_queue)
+ && ngx_queue_empty(&r->srv_resend_queue)
#if (NGX_HAVE_INET6)
&& ngx_queue_empty(&r->addr6_resend_queue)
#endif
@@ -2946,7 +2955,11 @@
ctx->srvs = srvs;
ctx->nsrvs = rn->nsrvs;
- for (i = 0; i < rn->nsrvs; i++) {
+ if (ctx->event && ctx->event->timer_set) {
+ ngx_del_timer(ctx->event);
+ }
+
+ for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len);
if (srvs[i].name.data == NULL) {
goto failed;
@@ -2965,7 +2978,7 @@
cctx->handler = ngx_resolver_srv_names_handler;
cctx->data = ctx;
cctx->srvs = &srvs[i];
- cctx->timeout = 0;
+ cctx->timeout = ctx->timeout;
srvs[i].priority = rn->u.srvs[i].priority;
srvs[i].weight = rn->u.srvs[i].weight;
@@ -4064,7 +4077,7 @@
#endif
if (rn->nsrvs) {
- for (i = 0; i < rn->nsrvs; i++) {
+ for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
if (rn->u.srvs[i].name.data) {
ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
}
@@ -4193,10 +4206,10 @@
d = 0;
}
- if (j == rn->naddrs) {
+ if (j == (ngx_uint_t) rn->naddrs) {
j = 0;
}
- } while (++i < rn->naddrs);
+ } while (++i < (ngx_uint_t) rn->naddrs);
}
#if (NGX_HAVE_INET6)
diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c
index 66faecc..1d4ce2b 100644
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -101,7 +101,7 @@
}
/**/
- pool->min_size = 1 << pool->min_shift;
+ pool->min_size = (size_t) 1 << pool->min_shift;
slots = ngx_slab_slots(pool);
@@ -473,7 +473,7 @@
case NGX_SLAB_SMALL:
shift = slab & NGX_SLAB_SHIFT_MASK;
- size = 1 << shift;
+ size = (size_t) 1 << shift;
if ((uintptr_t) p & (size - 1)) {
goto wrong_chunk;
@@ -568,7 +568,7 @@
case NGX_SLAB_BIG:
shift = slab & NGX_SLAB_SHIFT_MASK;
- size = 1 << shift;
+ size = (size_t) 1 << shift;
if ((uintptr_t) p & (size - 1)) {
goto wrong_chunk;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index d75b7f0..a2fa97d 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2859,7 +2859,8 @@
ngx_int_t
ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
{
- u_char buf[48];
+ u_char buf[80];
+ size_t size;
ssize_t n;
ngx_str_t *path;
ngx_file_t file;
@@ -2902,13 +2903,15 @@
goto failed;
}
- if (ngx_file_size(&fi) != 48) {
+ size = ngx_file_size(&fi);
+
+ if (size != 48 && size != 80) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "\"%V\" must be 48 bytes", &file.name);
+ "\"%V\" must be 48 or 80 bytes", &file.name);
goto failed;
}
- n = ngx_read_file(&file, buf, 48, 0);
+ n = ngx_read_file(&file, buf, size, 0);
if (n == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
@@ -2916,10 +2919,10 @@
goto failed;
}
- if (n != 48) {
+ if ((size_t) n != size) {
ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
ngx_read_file_n " \"%V\" returned only "
- "%z bytes instead of 48", &file.name, n);
+ "%z bytes instead of %uz", &file.name, n, size);
goto failed;
}
@@ -2928,9 +2931,18 @@
goto failed;
}
- ngx_memcpy(key->name, buf, 16);
- ngx_memcpy(key->aes_key, buf + 16, 16);
- ngx_memcpy(key->hmac_key, buf + 32, 16);
+ if (size == 48) {
+ key->size = 48;
+ ngx_memcpy(key->name, buf, 16);
+ ngx_memcpy(key->aes_key, buf + 16, 16);
+ ngx_memcpy(key->hmac_key, buf + 32, 16);
+
+ } else {
+ key->size = 80;
+ ngx_memcpy(key->name, buf, 16);
+ ngx_memcpy(key->hmac_key, buf + 16, 32);
+ ngx_memcpy(key->aes_key, buf + 48, 32);
+ }
if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
@@ -2975,6 +2987,7 @@
unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
HMAC_CTX *hctx, int enc)
{
+ size_t size;
SSL_CTX *ssl_ctx;
ngx_uint_t i;
ngx_array_t *keys;
@@ -2989,7 +3002,6 @@
c = ngx_ssl_get_connection(ssl_conn);
ssl_ctx = c->ssl->session_ctx;
- cipher = EVP_aes_128_cbc();
#ifdef OPENSSL_NO_SHA256
digest = EVP_sha1();
#else
@@ -3011,6 +3023,15 @@
ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
SSL_session_reused(ssl_conn) ? "reused" : "new");
+ if (key[0].size == 48) {
+ cipher = EVP_aes_128_cbc();
+ size = 16;
+
+ } else {
+ cipher = EVP_aes_256_cbc();
+ size = 32;
+ }
+
if (RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)) != 1) {
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "RAND_bytes() failed");
return -1;
@@ -3023,12 +3044,12 @@
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
- if (HMAC_Init_ex(hctx, key[0].hmac_key, 16, digest, NULL) != 1) {
+ if (HMAC_Init_ex(hctx, key[0].hmac_key, size, digest, NULL) != 1) {
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed");
return -1;
}
#else
- HMAC_Init_ex(hctx, key[0].hmac_key, 16, digest, NULL);
+ HMAC_Init_ex(hctx, key[0].hmac_key, size, digest, NULL);
#endif
ngx_memcpy(name, key[0].name, 16);
@@ -3057,13 +3078,22 @@
ngx_hex_dump(buf, key[i].name, 16) - buf, buf,
(i == 0) ? " (default)" : "");
+ if (key[i].size == 48) {
+ cipher = EVP_aes_128_cbc();
+ size = 16;
+
+ } else {
+ cipher = EVP_aes_256_cbc();
+ size = 32;
+ }
+
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
- if (HMAC_Init_ex(hctx, key[i].hmac_key, 16, digest, NULL) != 1) {
+ if (HMAC_Init_ex(hctx, key[i].hmac_key, size, digest, NULL) != 1) {
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "HMAC_Init_ex() failed");
return -1;
}
#else
- HMAC_Init_ex(hctx, key[i].hmac_key, 16, digest, NULL);
+ HMAC_Init_ex(hctx, key[i].hmac_key, size, digest, NULL);
#endif
if (EVP_DecryptInit_ex(ectx, cipher, NULL, key[i].aes_key, iv) != 1) {
@@ -4052,7 +4082,7 @@
ASN1_TIME *asn1time)
{
BIO *bio;
- u_char *value;
+ char *value;
size_t len;
time_t time;
@@ -4072,9 +4102,9 @@
BIO_write(bio, "Tue ", sizeof("Tue ") - 1);
ASN1_TIME_print(bio, asn1time);
- len = BIO_get_mem_data(bio, (char **) &value);
+ len = BIO_get_mem_data(bio, &value);
- time = ngx_parse_http_time(value, len);
+ time = ngx_parse_http_time((u_char *) value, len);
BIO_free(bio);
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index c022307..e093e10 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -117,9 +117,10 @@
#ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
typedef struct {
+ size_t size;
u_char name[16];
- u_char aes_key[16];
- u_char hmac_key[16];
+ u_char hmac_key[32];
+ u_char aes_key[32];
} ngx_ssl_session_ticket_key_t;
#endif
diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
index 2100516..d332c11 100644
--- a/src/event/ngx_event_openssl_stapling.c
+++ b/src/event/ngx_event_openssl_stapling.c
@@ -773,7 +773,7 @@
ngx_ssl_stapling_time(ASN1_GENERALIZEDTIME *asn1time)
{
BIO *bio;
- u_char *value;
+ char *value;
size_t len;
time_t time;
@@ -795,7 +795,7 @@
ASN1_GENERALIZEDTIME_print(bio, asn1time);
len = BIO_get_mem_data(bio, &value);
- time = ngx_parse_http_time(value, len);
+ time = ngx_parse_http_time((u_char *) value, len);
BIO_free(bio);
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 012a0fb..895a52d 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1067,7 +1067,7 @@
u_char *location;
ngx_http_core_loc_conf_t *clcf;
- r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
+ r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
return NGX_ERROR;
}
@@ -1086,11 +1086,8 @@
ngx_memcpy(location, r->uri.data, r->uri.len);
}
- /*
- * we do not need to set the r->headers_out.location->hash and
- * r->headers_out.location->key fields
- */
-
+ r->headers_out.location->hash = 1;
+ ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value.len = r->uri.len;
r->headers_out.location->value.data = location;
diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c
index c42fb08..ff8572b 100644
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -126,12 +126,16 @@
ngx_http_log_op_t *op);
static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
- ngx_http_log_op_t *op, ngx_str_t *value);
+ ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
uintptr_t data);
static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size);
+static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
+ uintptr_t data);
+static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
+ ngx_http_log_op_t *op);
static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
@@ -909,7 +913,7 @@
static ngx_int_t
ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
- ngx_str_t *value)
+ ngx_str_t *value, ngx_uint_t json)
{
ngx_int_t index;
@@ -919,8 +923,16 @@
}
op->len = 0;
- op->getlen = ngx_http_log_variable_getlen;
- op->run = ngx_http_log_variable;
+
+ if (json) {
+ op->getlen = ngx_http_log_json_variable_getlen;
+ op->run = ngx_http_log_json_variable;
+
+ } else {
+ op->getlen = ngx_http_log_variable_getlen;
+ op->run = ngx_http_log_variable;
+ }
+
op->data = index;
return NGX_OK;
@@ -1028,6 +1040,47 @@
}
+static size_t
+ngx_http_log_json_variable_getlen(ngx_http_request_t *r, uintptr_t data)
+{
+ uintptr_t len;
+ ngx_http_variable_value_t *value;
+
+ value = ngx_http_get_indexed_variable(r, data);
+
+ if (value == NULL || value->not_found) {
+ return 0;
+ }
+
+ len = ngx_escape_json(NULL, value->data, value->len);
+
+ value->escape = len ? 1 : 0;
+
+ return value->len + len;
+}
+
+
+static u_char *
+ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
+ ngx_http_log_op_t *op)
+{
+ ngx_http_variable_value_t *value;
+
+ value = ngx_http_get_indexed_variable(r, op->data);
+
+ if (value == NULL || value->not_found) {
+ return buf;
+ }
+
+ if (value->escape == 0) {
+ return ngx_cpymem(buf, value->data, value->len);
+
+ } else {
+ return (u_char *) ngx_escape_json(buf, value->data, value->len);
+ }
+}
+
+
static void *
ngx_http_log_create_main_conf(ngx_conf_t *cf)
{
@@ -1491,12 +1544,28 @@
size_t i, len;
ngx_str_t *value, var;
ngx_int_t *flush;
- ngx_uint_t bracket;
+ ngx_uint_t bracket, json;
ngx_http_log_op_t *op;
ngx_http_log_var_t *v;
+ json = 0;
value = args->elts;
+ if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
+ data = value[s].data + 7;
+
+ if (ngx_strcmp(data, "json") == 0) {
+ json = 1;
+
+ } else if (ngx_strcmp(data, "default") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown log format escaping \"%s\"", data);
+ return NGX_CONF_ERROR;
+ }
+
+ s++;
+ }
+
for ( /* void */ ; s < args->nelts; s++) {
i = 0;
@@ -1575,7 +1644,9 @@
}
}
- if (ngx_http_log_variable_compile(cf, op, &var) != NGX_OK) {
+ if (ngx_http_log_variable_compile(cf, op, &var, json)
+ != NGX_OK)
+ {
return NGX_CONF_ERROR;
}
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index f79c4ae..07b9580 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -150,7 +150,7 @@
ngx_http_clear_location(r);
- r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
+ r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -182,11 +182,8 @@
}
}
- /*
- * we do not need to set the r->headers_out.location->hash and
- * r->headers_out.location->key fields
- */
-
+ r->headers_out.location->hash = 1;
+ ngx_str_set(&r->headers_out.location->key, "Location");
r->headers_out.location->value.len = len;
r->headers_out.location->value.data = location;
diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c
index e8d1d80..de58c6f 100644
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -645,7 +645,7 @@
start = offset - (ngx_int_t) tables->min_match_len + 1;
- i = ngx_max(tables->index[c], ctx->index);
+ i = ngx_max((ngx_uint_t) tables->index[c], ctx->index);
j = tables->index[c + 1];
while (i != j) {
@@ -978,7 +978,7 @@
}
c = match[i].match.data[tables->min_match_len - 1];
- while (ch <= c) {
+ while (ch <= (ngx_uint_t) c) {
tables->index[ch++] = (u_char) i;
}
}
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index ba559f2..c036389 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -457,7 +457,10 @@
use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
- n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;
+ n = 1 /* find config phase */
+ + use_rewrite /* post rewrite phase */
+ + use_access /* post access phase */
+ + cmcf->try_files;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
n += cmcf->phases[i].handlers.nelts;
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 9f40173..dda23e0 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -542,6 +542,13 @@
offsetof(ngx_http_core_loc_conf_t, reset_timedout_connection),
NULL },
+ { ngx_string("absolute_redirect"),
+ 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_core_loc_conf_t, absolute_redirect),
+ NULL },
+
{ ngx_string("server_name_in_redirect"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -976,10 +983,8 @@
return NGX_OK;
}
- /*
- * we do not need to set the r->headers_out.location->hash and
- * r->headers_out.location->key fields
- */
+ r->headers_out.location->hash = 1;
+ ngx_str_set(&r->headers_out.location->key, "Location");
if (r->args.len == 0) {
r->headers_out.location->value = clcf->name;
@@ -3563,6 +3568,7 @@
clcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
clcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
clcf->reset_timedout_connection = NGX_CONF_UNSET;
+ clcf->absolute_redirect = NGX_CONF_UNSET;
clcf->server_name_in_redirect = NGX_CONF_UNSET;
clcf->port_in_redirect = NGX_CONF_UNSET;
clcf->msie_padding = NGX_CONF_UNSET;
@@ -3825,6 +3831,8 @@
ngx_conf_merge_value(conf->reset_timedout_connection,
prev->reset_timedout_connection, 0);
+ ngx_conf_merge_value(conf->absolute_redirect,
+ prev->absolute_redirect, 1);
ngx_conf_merge_value(conf->server_name_in_redirect,
prev->server_name_in_redirect, 0);
ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 1);
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 2bb0746..7ae0ce3 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -385,6 +385,7 @@
ngx_flag_t tcp_nopush; /* tcp_nopush */
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
+ ngx_flag_t absolute_redirect; /* absolute_redirect */
ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */
ngx_flag_t port_in_redirect; /* port_in_redirect */
ngx_flag_t msie_padding; /* msie_padding */
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 3c8ad7d..a5a9300 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -553,7 +553,7 @@
return NGX_DECLINED;
}
- if (h->crc32 != c->crc32 || h->header_start != c->header_start) {
+ if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"cache file \"%s\" has md5 collision", c->file.name.data);
return NGX_DECLINED;
@@ -1495,8 +1495,8 @@
if (h.version != NGX_HTTP_CACHE_VERSION
|| h.last_modified != c->last_modified
|| h.crc32 != c->crc32
- || h.header_start != c->header_start
- || h.body_start != c->body_start)
+ || (size_t) h.header_start != c->header_start
+ || (size_t) h.body_start != c->body_start)
{
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http file cache \"%s\" content changed",
diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c
index fc4d3e9..4c3f5e2 100644
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -313,7 +313,8 @@
if (r->headers_out.location
&& r->headers_out.location->value.len
- && r->headers_out.location->value.data[0] == '/')
+ && r->headers_out.location->value.data[0] == '/'
+ && clcf->absolute_redirect)
{
r->headers_out.location->hash = 0;
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index c2b1658..c1a0b4c 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -356,11 +356,11 @@
n = sc->source->data[i] - '0';
- if (sc->captures_mask & (1 << n)) {
+ if (sc->captures_mask & ((ngx_uint_t) 1 << n)) {
sc->dup_capture = 1;
}
- sc->captures_mask |= 1 << n;
+ sc->captures_mask |= (ngx_uint_t) 1 << n;
if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) {
return NGX_ERROR;
diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h
index 46592ab..a5116d7 100644
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -121,16 +121,16 @@
uintptr_t status;
uintptr_t next;
- uintptr_t test:1;
- uintptr_t negative_test:1;
- uintptr_t uri:1;
- uintptr_t args:1;
+ unsigned test:1;
+ unsigned negative_test:1;
+ unsigned uri:1;
+ unsigned args:1;
/* add the r->args to the new arguments */
- uintptr_t add_args:1;
+ unsigned add_args:1;
- uintptr_t redirect:1;
- uintptr_t break_cycle:1;
+ unsigned redirect:1;
+ unsigned break_cycle:1;
ngx_str_t name;
} ngx_http_script_regex_code_t;
@@ -139,13 +139,13 @@
typedef struct {
ngx_http_script_code_pt code;
- uintptr_t uri:1;
- uintptr_t args:1;
+ unsigned uri:1;
+ unsigned args:1;
/* add the r->args to the new arguments */
- uintptr_t add_args:1;
+ unsigned add_args:1;
- uintptr_t redirect:1;
+ unsigned redirect:1;
} ngx_http_script_regex_end_code_t;
#endif
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 0b7c911..dc58eea 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -4933,8 +4933,8 @@
}
/*
- * we do not set r->headers_out.location here to avoid the handling
- * the local redirects without a host name by ngx_http_header_filter()
+ * we do not set r->headers_out.location here to avoid handling
+ * relative redirects in ngx_http_header_filter()
*/
return NGX_OK;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 580b918..251ddda 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -366,6 +366,9 @@
ngx_http_variable("1");
+static ngx_uint_t ngx_http_variable_depth = 100;
+
+
ngx_http_variable_t *
ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
{
@@ -517,9 +520,20 @@
v = cmcf->variables.elts;
+ if (ngx_http_variable_depth == 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "cycle while evaluating variable \"%V\"",
+ &v[index].name);
+ return NULL;
+ }
+
+ ngx_http_variable_depth--;
+
if (v[index].get_handler(r, &r->variables[index], v[index].data)
== NGX_OK)
{
+ ngx_http_variable_depth++;
+
if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
r->variables[index].no_cacheable = 1;
}
@@ -527,6 +541,8 @@
return &r->variables[index];
}
+ ngx_http_variable_depth++;
+
r->variables[index].valid = 0;
r->variables[index].not_found = 1;
@@ -568,17 +584,25 @@
if (v) {
if (v->flags & NGX_HTTP_VAR_INDEXED) {
return ngx_http_get_flushed_variable(r, v->index);
+ }
- } else {
-
- vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
-
- if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
- return vv;
- }
-
+ if (ngx_http_variable_depth == 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "cycle while evaluating variable \"%V\"", name);
return NULL;
}
+
+ ngx_http_variable_depth--;
+
+ vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
+
+ if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
+ ngx_http_variable_depth++;
+ return vv;
+ }
+
+ ngx_http_variable_depth++;
+ return NULL;
}
vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
index bfe1815..5433481 100644
--- a/src/http/v2/ngx_http_v2_filter_module.c
+++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -266,7 +266,9 @@
if (r->headers_out.location && r->headers_out.location->value.len) {
- if (r->headers_out.location->value.data[0] == '/') {
+ if (r->headers_out.location->value.data[0] == '/'
+ && clcf->absolute_redirect)
+ {
if (clcf->server_name_in_redirect) {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
host = cscf->server_name;
diff --git a/src/mail/ngx_mail_smtp_module.c b/src/mail/ngx_mail_smtp_module.c
index f03bd90..3b5a2d8 100644
--- a/src/mail/ngx_mail_smtp_module.c
+++ b/src/mail/ngx_mail_smtp_module.c
@@ -280,7 +280,7 @@
p = ngx_cpymem(p, conf->capability.data, conf->capability.len);
- p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+ ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
p = conf->starttls_capability.data
+ (last - conf->capability.data) + 3;
diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h
index f5b5950..4824d05 100644
--- a/src/os/win32/ngx_win32_config.h
+++ b/src/os/win32/ngx_win32_config.h
@@ -51,13 +51,14 @@
/* GCC MinGW's stdio.h includes sys/types.h */
#define _OFF_T_
+#define __have_typedef_off_t
#endif
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#ifdef __MINGW64_VERSION_MAJOR
+#ifdef __GNUC__
#include <stdint.h>
#endif
#include <ctype.h>
@@ -87,12 +88,21 @@
/* 'type cast': from data pointer to function pointer */
#pragma warning(disable:4055)
+/* 'function' : different 'const' qualifiers */
+#pragma warning(disable:4090)
+
/* unreferenced formal parameter */
#pragma warning(disable:4100)
/* FD_SET() and FD_CLR(): conditional expression is constant */
#pragma warning(disable:4127)
+/* conversion from 'type1' to 'type2', possible loss of data */
+#pragma warning(disable:4244)
+
+/* conversion from 'size_t' to 'type', possible loss of data */
+#pragma warning(disable:4267)
+
/* array is too small to include a terminating null character */
#pragma warning(disable:4295)
@@ -118,6 +128,9 @@
/* unreferenced formal parameter */
#pragma warn -8057
+/* suspicious pointer arithmetic */
+#pragma warn -8072
+
#endif
@@ -151,7 +164,7 @@
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
-#if !defined(__WATCOMC__) && !defined(__MINGW64_VERSION_MAJOR)
+#if __BORLANDC__
typedef int intptr_t;
typedef u_int uintptr_t;
#endif
@@ -184,9 +197,13 @@
#endif
-#ifndef __MINGW64_VERSION_MAJOR
+#ifndef __GNUC__
+#ifdef _WIN64
+typedef __int64 ssize_t;
+#else
typedef int ssize_t;
#endif
+#endif
typedef uint32_t in_addr_t;
diff --git a/src/stream/ngx_stream_log_module.c b/src/stream/ngx_stream_log_module.c
index 26e6d22..a4b67d0 100644
--- a/src/stream/ngx_stream_log_module.c
+++ b/src/stream/ngx_stream_log_module.c
@@ -106,12 +106,16 @@
static void ngx_stream_log_flush_handler(ngx_event_t *ev);
static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
- ngx_stream_log_op_t *op, ngx_str_t *value);
+ ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
uintptr_t data);
static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
ngx_stream_log_op_t *op);
static uintptr_t ngx_stream_log_escape(u_char *dst, u_char *src, size_t size);
+static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
+ uintptr_t data);
+static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
+ u_char *buf, ngx_stream_log_op_t *op);
static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
@@ -686,7 +690,7 @@
static ngx_int_t
ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
- ngx_str_t *value)
+ ngx_str_t *value, ngx_uint_t json)
{
ngx_int_t index;
@@ -696,8 +700,16 @@
}
op->len = 0;
- op->getlen = ngx_stream_log_variable_getlen;
- op->run = ngx_stream_log_variable;
+
+ if (json) {
+ op->getlen = ngx_stream_log_json_variable_getlen;
+ op->run = ngx_stream_log_json_variable;
+
+ } else {
+ op->getlen = ngx_stream_log_variable_getlen;
+ op->run = ngx_stream_log_variable;
+ }
+
op->data = index;
return NGX_OK;
@@ -806,6 +818,47 @@
}
+static size_t
+ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s, uintptr_t data)
+{
+ uintptr_t len;
+ ngx_stream_variable_value_t *value;
+
+ value = ngx_stream_get_indexed_variable(s, data);
+
+ if (value == NULL || value->not_found) {
+ return 0;
+ }
+
+ len = ngx_escape_json(NULL, value->data, value->len);
+
+ value->escape = len ? 1 : 0;
+
+ return value->len + len;
+}
+
+
+static u_char *
+ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
+ ngx_stream_log_op_t *op)
+{
+ ngx_stream_variable_value_t *value;
+
+ value = ngx_stream_get_indexed_variable(s, op->data);
+
+ if (value == NULL || value->not_found) {
+ return buf;
+ }
+
+ if (value->escape == 0) {
+ return ngx_cpymem(buf, value->data, value->len);
+
+ } else {
+ return (u_char *) ngx_escape_json(buf, value->data, value->len);
+ }
+}
+
+
static void *
ngx_stream_log_create_main_conf(ngx_conf_t *cf)
{
@@ -1220,11 +1273,27 @@
size_t i, len;
ngx_str_t *value, var;
ngx_int_t *flush;
- ngx_uint_t bracket;
+ ngx_uint_t bracket, json;
ngx_stream_log_op_t *op;
+ json = 0;
value = args->elts;
+ if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
+ data = value[s].data + 7;
+
+ if (ngx_strcmp(data, "json") == 0) {
+ json = 1;
+
+ } else if (ngx_strcmp(data, "default") != 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown log format escaping \"%s\"", data);
+ return NGX_CONF_ERROR;
+ }
+
+ s++;
+ }
+
for ( /* void */ ; s < args->nelts; s++) {
i = 0;
@@ -1289,7 +1358,9 @@
goto invalid;
}
- if (ngx_stream_log_variable_compile(cf, op, &var) != NGX_OK) {
+ if (ngx_stream_log_variable_compile(cf, op, &var, json)
+ != NGX_OK)
+ {
return NGX_CONF_ERROR;
}
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index c03b515..bfd78d5 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -808,6 +808,11 @@
u->state->connect_time = ngx_current_msec - u->state->response_time;
+ if (u->peer.notify) {
+ u->peer.notify(&u->peer, u->peer.data,
+ NGX_STREAM_UPSTREAM_NOTIFY_CONNECT);
+ }
+
c->log->action = "proxying connection";
if (u->upstream_buf.start == NULL) {
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index 9191641..fb653c5 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -49,6 +49,15 @@
};
+static ngx_conf_enum_t ngx_stream_ssl_verify[] = {
+ { ngx_string("off"), 0 },
+ { ngx_string("on"), 1 },
+ { ngx_string("optional"), 2 },
+ { ngx_string("optional_no_ca"), 3 },
+ { ngx_null_string, 0 }
+};
+
+
static ngx_command_t ngx_stream_ssl_commands[] = {
{ ngx_string("ssl_handshake_timeout"),
@@ -107,6 +116,34 @@
offsetof(ngx_stream_ssl_conf_t, ciphers),
NULL },
+ { ngx_string("ssl_verify_client"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_enum_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_ssl_conf_t, verify),
+ &ngx_stream_ssl_verify },
+
+ { ngx_string("ssl_verify_depth"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_ssl_conf_t, verify_depth),
+ NULL },
+
+ { ngx_string("ssl_client_certificate"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_ssl_conf_t, client_certificate),
+ NULL },
+
+ { ngx_string("ssl_trusted_certificate"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_ssl_conf_t, trusted_certificate),
+ NULL },
+
{ ngx_string("ssl_prefer_server_ciphers"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -142,6 +179,13 @@
offsetof(ngx_stream_ssl_conf_t, session_timeout),
NULL },
+ { ngx_string("ssl_crl"),
+ NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ offsetof(ngx_stream_ssl_conf_t, crl),
+ NULL },
+
ngx_null_command
};
@@ -197,6 +241,37 @@
{ ngx_string("ssl_server_name"), NULL, ngx_stream_ssl_variable,
(uintptr_t) ngx_ssl_get_server_name, NGX_STREAM_VAR_CHANGEABLE, 0 },
+ { ngx_string("ssl_client_cert"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_certificate, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_raw_cert"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_raw_certificate,
+ NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_s_dn"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_subject_dn, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_i_dn"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_issuer_dn, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_serial"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_serial_number, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_fingerprint"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_fingerprint, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_verify"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_client_verify, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_v_start"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_client_v_start, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_v_end"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_client_v_end, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
+ { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable,
+ (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 },
+
{ ngx_null_string, NULL, NULL, 0, 0, 0 }
};
@@ -207,6 +282,8 @@
static ngx_int_t
ngx_stream_ssl_handler(ngx_stream_session_t *s)
{
+ long rc;
+ X509 *cert;
ngx_connection_t *c;
ngx_stream_ssl_conf_t *sslcf;
@@ -227,6 +304,37 @@
return ngx_stream_ssl_init_connection(&sslcf->ssl, c);
}
+ if (sslcf->verify) {
+ rc = SSL_get_verify_result(c->ssl->connection);
+
+ if (rc != X509_V_OK
+ && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc)))
+ {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "client SSL certificate verify error: (%l:%s)",
+ rc, X509_verify_cert_error_string(rc));
+
+ ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
+ (SSL_get0_session(c->ssl->connection)));
+ return NGX_ERROR;
+ }
+
+ if (sslcf->verify == 1) {
+ cert = SSL_get_peer_certificate(c->ssl->connection);
+
+ if (cert == NULL) {
+ ngx_log_error(NGX_LOG_INFO, c->log, 0,
+ "client sent no required SSL certificate");
+
+ ngx_ssl_remove_cached_session(sslcf->ssl.ctx,
+ (SSL_get0_session(c->ssl->connection)));
+ return NGX_ERROR;
+ }
+
+ X509_free(cert);
+ }
+ }
+
return NGX_OK;
}
@@ -384,6 +492,9 @@
* scf->protocols = 0;
* scf->dhparam = { 0, NULL };
* scf->ecdh_curve = { 0, NULL };
+ * scf->client_certificate = { 0, NULL };
+ * scf->trusted_certificate = { 0, NULL };
+ * scf->crl = { 0, NULL };
* scf->ciphers = { 0, NULL };
* scf->shm_zone = NULL;
*/
@@ -393,6 +504,8 @@
scf->certificate_keys = NGX_CONF_UNSET_PTR;
scf->passwords = NGX_CONF_UNSET_PTR;
scf->prefer_server_ciphers = NGX_CONF_UNSET;
+ scf->verify = NGX_CONF_UNSET_UINT;
+ scf->verify_depth = NGX_CONF_UNSET_UINT;
scf->builtin_session_cache = NGX_CONF_UNSET;
scf->session_timeout = NGX_CONF_UNSET;
scf->session_tickets = NGX_CONF_UNSET;
@@ -423,6 +536,9 @@
(NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+ ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
+ ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
+
ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL);
ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys,
NULL);
@@ -431,6 +547,12 @@
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
+ ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
+ "");
+ ngx_conf_merge_str_value(conf->trusted_certificate,
+ prev->trusted_certificate, "");
+ ngx_conf_merge_str_value(conf->crl, prev->crl, "");
+
ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
NGX_DEFAULT_ECDH_CURVE);
@@ -480,6 +602,35 @@
return NGX_CONF_ERROR;
}
+ if (conf->verify) {
+
+ if (conf->client_certificate.len == 0 && conf->verify != 3) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no ssl_client_certificate for ssl_client_verify");
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_client_certificate(cf, &conf->ssl,
+ &conf->client_certificate,
+ conf->verify_depth)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_trusted_certificate(cf, &conf->ssl,
+ &conf->trusted_certificate,
+ conf->verify_depth)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
if (ngx_ssl_dhparam(cf, &conf->ssl, &conf->dhparam) != NGX_OK) {
return NGX_CONF_ERROR;
}
diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h
index 9b1c41a..65f5d45 100644
--- a/src/stream/ngx_stream_ssl_module.h
+++ b/src/stream/ngx_stream_ssl_module.h
@@ -23,6 +23,9 @@
ngx_uint_t protocols;
+ ngx_uint_t verify;
+ ngx_uint_t verify_depth;
+
ssize_t builtin_session_cache;
time_t session_timeout;
@@ -32,6 +35,9 @@
ngx_str_t dhparam;
ngx_str_t ecdh_curve;
+ ngx_str_t client_certificate;
+ ngx_str_t trusted_certificate;
+ ngx_str_t crl;
ngx_str_t ciphers;
diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c
index e26c518..2040b4f 100644
--- a/src/stream/ngx_stream_ssl_preread_module.c
+++ b/src/stream/ngx_stream_ssl_preread_module.c
@@ -142,7 +142,7 @@
return NGX_DECLINED;
}
- if (p[1] != 3 || p[2] == 0) {
+ if (p[1] != 3) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: unsupported SSL version");
return NGX_DECLINED;
diff --git a/src/stream/ngx_stream_upstream.h b/src/stream/ngx_stream_upstream.h
index 7a36775..283ffd8 100644
--- a/src/stream/ngx_stream_upstream.h
+++ b/src/stream/ngx_stream_upstream.h
@@ -24,6 +24,9 @@
#define NGX_STREAM_UPSTREAM_MAX_CONNS 0x0100
+#define NGX_STREAM_UPSTREAM_NOTIFY_CONNECT 0x1
+
+
typedef struct {
ngx_array_t upstreams;
/* ngx_stream_upstream_srv_conf_t */
diff --git a/src/stream/ngx_stream_upstream_round_robin.c b/src/stream/ngx_stream_upstream_round_robin.c
index a4d539d..e4a6e76 100644
--- a/src/stream/ngx_stream_upstream_round_robin.c
+++ b/src/stream/ngx_stream_upstream_round_robin.c
@@ -16,6 +16,8 @@
static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_get_peer(
ngx_stream_upstream_rr_peer_data_t *rrp);
+static void ngx_stream_upstream_notify_round_robin_peer(
+ ngx_peer_connection_t *pc, void *data, ngx_uint_t state);
#if (NGX_STREAM_SSL)
@@ -288,6 +290,7 @@
s->upstream->peer.get = ngx_stream_upstream_get_round_robin_peer;
s->upstream->peer.free = ngx_stream_upstream_free_round_robin_peer;
+ s->upstream->peer.notify = ngx_stream_upstream_notify_round_robin_peer;
s->upstream->peer.tries = ngx_stream_upstream_tries(rrp->peers);
#if (NGX_STREAM_SSL)
s->upstream->peer.set_session =
@@ -659,6 +662,32 @@
}
+static void
+ngx_stream_upstream_notify_round_robin_peer(ngx_peer_connection_t *pc,
+ void *data, ngx_uint_t type)
+{
+ ngx_stream_upstream_rr_peer_data_t *rrp = data;
+
+ ngx_stream_upstream_rr_peer_t *peer;
+
+ peer = rrp->current;
+
+ if (type == NGX_STREAM_UPSTREAM_NOTIFY_CONNECT
+ && pc->connection->type == SOCK_STREAM)
+ {
+ ngx_stream_upstream_rr_peers_rlock(rrp->peers);
+ ngx_stream_upstream_rr_peer_lock(rrp->peers, peer);
+
+ if (peer->accessed < peer->checked) {
+ peer->fails = 0;
+ }
+
+ ngx_stream_upstream_rr_peer_unlock(rrp->peers, peer);
+ ngx_stream_upstream_rr_peers_unlock(rrp->peers);
+ }
+}
+
+
#if (NGX_STREAM_SSL)
static ngx_int_t
diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c
index aa5361d..9dc93ee 100644
--- a/src/stream/ngx_stream_variables.c
+++ b/src/stream/ngx_stream_variables.c
@@ -119,6 +119,9 @@
ngx_stream_variable("1");
+static ngx_uint_t ngx_stream_variable_depth = 100;
+
+
ngx_stream_variable_t *
ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
{
@@ -270,9 +273,20 @@
v = cmcf->variables.elts;
+ if (ngx_stream_variable_depth == 0) {
+ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+ "cycle while evaluating variable \"%V\"",
+ &v[index].name);
+ return NULL;
+ }
+
+ ngx_stream_variable_depth--;
+
if (v[index].get_handler(s, &s->variables[index], v[index].data)
== NGX_OK)
{
+ ngx_stream_variable_depth++;
+
if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
s->variables[index].no_cacheable = 1;
}
@@ -280,6 +294,8 @@
return &s->variables[index];
}
+ ngx_stream_variable_depth++;
+
s->variables[index].valid = 0;
s->variables[index].not_found = 1;
@@ -322,18 +338,26 @@
if (v) {
if (v->flags & NGX_STREAM_VAR_INDEXED) {
return ngx_stream_get_flushed_variable(s, v->index);
+ }
- } else {
-
- vv = ngx_palloc(s->connection->pool,
- sizeof(ngx_stream_variable_value_t));
-
- if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
- return vv;
- }
-
+ if (ngx_stream_variable_depth == 0) {
+ ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+ "cycle while evaluating variable \"%V\"", name);
return NULL;
}
+
+ ngx_stream_variable_depth--;
+
+ vv = ngx_palloc(s->connection->pool,
+ sizeof(ngx_stream_variable_value_t));
+
+ if (vv && v->get_handler(s, vv, v->data) == NGX_OK) {
+ ngx_stream_variable_depth++;
+ return vv;
+ }
+
+ ngx_stream_variable_depth++;
+ return NULL;
}
vv = ngx_palloc(s->connection->pool, sizeof(ngx_stream_variable_value_t));