Merge branch 'nginx' (nginx-1.15.9).
Change-Id: I95518364d57aef7427d33ea61a5c6f48545e402b
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 0f43222..1228a94 100644
--- a/.hgtags
+++ b/.hgtags
@@ -434,3 +434,4 @@
2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6
051a039ce1c7e09144de4a4846669ec7116cecea release-1.15.7
ee551e3f6dba336c0d875e266d7d55385f379b42 release-1.15.8
+d2fd76709909767fc727a5b4affcf1dc9ca488a7 release-1.15.9
diff --git a/BUILD b/BUILD
index b1f4c83..a830a04 100644
--- a/BUILD
+++ b/BUILD
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -1537,5 +1537,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.15.8",
+ version = "1.15.9",
)
diff --git a/LICENSE b/LICENSE
index e8d4bc5..7abb171 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2002-2018 Igor Sysoev
- * Copyright (C) 2011-2018 Nginx, Inc.
- * Copyright (C) 2015-2018 Google Inc.
+ * Copyright (C) 2002-2019 Igor Sysoev
+ * Copyright (C) 2011-2019 Nginx, Inc.
+ * Copyright (C) 2015-2019 Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/README.md b/README.md
index 8ab737b..09da59b 100644
--- a/README.md
+++ b/README.md
@@ -21,9 +21,9 @@
## License
- Copyright (C) 2002-2018 Igor Sysoev
- Copyright (C) 2011-2018 Nginx, Inc.
- Copyright (C) 2015-2018 Google Inc.
+ Copyright (C) 2002-2019 Igor Sysoev
+ Copyright (C) 2011-2019 Nginx, Inc.
+ Copyright (C) 2015-2019 Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/WORKSPACE b/WORKSPACE
index abb72d5..513aac5 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
diff --git a/auto/make b/auto/make
index 7ddd100..34c40cd 100644
--- a/auto/make
+++ b/auto/make
@@ -229,7 +229,7 @@
binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext
$NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer
- \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
+ \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_binext$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
$ngx_rcc
$ngx_long_end
diff --git a/auto/os/win32 b/auto/os/win32
index a0c9862..3b6e2e8 100644
--- a/auto/os/win32
+++ b/auto/os/win32
@@ -11,6 +11,7 @@
OS_CONFIG="$WIN32_CONFIG"
NGX_ICONS="$NGX_WIN32_ICONS"
SELECT_SRCS=$WIN32_SELECT_SRCS
+POLL_SRCS=$WIN32_POLL_SRCS
ngx_pic_opt=
ngx_binext=".exe"
@@ -31,12 +32,7 @@
esac
EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE"
-EVENT_FOUND=YES
-
-if [ $EVENT_SELECT = NO ]; then
- CORE_SRCS="$CORE_SRCS $SELECT_SRCS"
- EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE"
-fi
+#EVENT_FOUND=YES
have=NGX_HAVE_INET6 . $NGX_AUTO/have
diff --git a/auto/sources b/auto/sources
index 9f9571e..8610764 100644
--- a/auto/sources
+++ b/auto/sources
@@ -105,6 +105,7 @@
POLL_MODULE=ngx_poll_module
POLL_SRCS=src/event/modules/ngx_poll_module.c
+WIN32_POLL_SRCS=src/event/modules/ngx_win32_poll_module.c
KQUEUE_MODULE=ngx_kqueue_module
KQUEUE_SRCS=src/event/modules/ngx_kqueue_module.c
diff --git a/build.bzl b/build.bzl
index 73549af..5f00eb8 100644
--- a/build.bzl
+++ b/build.bzl
@@ -1,4 +1,4 @@
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,7 @@
]
_NGX_BROTLI_BUILD_FILE = """
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -136,7 +136,7 @@
"""
_PCRE_BUILD_FILE = """
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -268,7 +268,7 @@
"""
_PKGOSS_BUILD_FILE = """
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -544,7 +544,7 @@
"""
_ZLIB_BUILD_FILE = """
-# Copyright (C) 2015-2018 Google Inc.
+# Copyright (C) 2015-2019 Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -673,9 +673,9 @@
name = "nginx_pkgoss",
build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
_PKGOSS_BUILD_FILE_TAIL,
- commit = "2456bf617acaa11b06c11481082797909b300f45", # nginx-1.15.8
+ commit = "894beef672e913605c6b93be022933c9ca22cd7b", # nginx-1.15.9
remote = "https://nginx.googlesource.com/nginx-pkgoss",
- shallow_since = "1545733310 +0300",
+ shallow_since = "1551190491 +0300",
)
def nginx_repositories_zlib(bind):
diff --git a/docs/text/LICENSE b/docs/text/LICENSE
index 9401174..c63e0ba 100644
--- a/docs/text/LICENSE
+++ b/docs/text/LICENSE
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2002-2018 Igor Sysoev
- * Copyright (C) 2011-2018 Nginx, Inc.
+ * Copyright (C) 2002-2019 Igor Sysoev
+ * Copyright (C) 2011-2019 Nginx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 4c471d8..e7dcf95 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,59 @@
<change_log title="nginx">
+<changes ver="1.15.9" date="2019-02-26">
+
+<change type="feature">
+<para lang="ru">
+директивы ssl_certificate и ssl_certificate_key
+поддерживают переменные.
+</para>
+<para lang="en">
+variables support
+in the "ssl_certificate" and "ssl_certificate_key" directives.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+метод poll теперь доступен на Windows
+при использовании Windows Vista и новее.
+</para>
+<para lang="en">
+the "poll" method is now available on Windows
+when using Windows Vista or newer.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если при использовании метода select на Windows
+происходила ошибка при установлении соединения с бэкендом,
+nginx ожидал истечения таймаута на установление соединения.
+</para>
+<para lang="en">
+if the "select" method was used on Windows
+and an error occurred while establishing a backend connection,
+nginx waited for the connection establishment timeout to expire.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+директивы proxy_upload_rate и proxy_download_rate
+в модуле stream
+работали некорректно при проксировании UDP-пакетов.
+</para>
+<para lang="en">
+the "proxy_upload_rate" and "proxy_download_rate" directives
+in the stream module
+worked incorrectly when proxying UDP datagrams.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.15.8" date="2018-12-25">
<change type="feature">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index d68ceca..bf91174 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,7 +6,7 @@
CC = cl
OBJS = objs.msvc8
-OPENSSL = openssl-1.0.2q
+OPENSSL = openssl-1.1.1b
ZLIB = zlib-1.2.11
PCRE = pcre-8.42
@@ -65,7 +65,6 @@
--with-cc-opt=-DFD_SETSIZE=1024 \
--with-pcre=$(OBJS)/lib/$(PCRE) \
--with-zlib=$(OBJS)/lib/$(ZLIB) \
- --with-select_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_addition_module \
diff --git a/src/core/nginx.h b/src/core/nginx.h
index b130fae..2795d87 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1015008
-#define NGINX_VERSION "1.15.8"
+#define nginx_version 1015009
+#define NGINX_VERSION "1.15.9"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index e92cd33..6d1629e 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -310,7 +310,7 @@
goto failed;
}
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, rv);
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", rv);
goto failed;
}
diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c
index 4023870..b8577ce 100644
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -635,10 +635,9 @@
goto fail;
}
- n = ((u_char *) p - pool->start) >> ngx_pagesize_shift;
size = slab & ~NGX_SLAB_PAGE_START;
- ngx_slab_free_pages(pool, &pool->pages[n], size);
+ ngx_slab_free_pages(pool, page, size);
ngx_slab_junk(p, size << ngx_pagesize_shift);
diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c
index 28c3c92..061c996 100644
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -250,9 +250,7 @@
ngx_memzero(&sev, sizeof(struct sigevent));
sev.sigev_notify = SIGEV_PORT;
-#if !(NGX_TEST_BUILD_EVENTPORT)
sev.sigev_value.sival_ptr = &pn;
-#endif
if (timer_create(CLOCK_REALTIME, &sev, &event_timer) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c
index 83e5f8d..a12c112 100644
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -86,7 +86,7 @@
}
if (event_list) {
- ngx_memcpy(list, event_list, sizeof(ngx_event_t *) * nevents);
+ ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents);
ngx_free(event_list);
}
diff --git a/src/event/modules/ngx_win32_poll_module.c b/src/event/modules/ngx_win32_poll_module.c
new file mode 100644
index 0000000..9fe867f
--- /dev/null
+++ b/src/event/modules/ngx_win32_poll_module.c
@@ -0,0 +1,435 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) Maxim Dounin
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer);
+static void ngx_poll_done(ngx_cycle_t *cycle);
+static ngx_int_t ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event,
+ ngx_uint_t flags);
+static ngx_int_t ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
+ ngx_uint_t flags);
+static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf);
+
+
+static struct pollfd *event_list;
+static ngx_connection_t **event_index;
+static ngx_uint_t nevents;
+
+
+static ngx_str_t poll_name = ngx_string("poll");
+
+static ngx_event_module_t ngx_poll_module_ctx = {
+ &poll_name,
+ NULL, /* create configuration */
+ ngx_poll_init_conf, /* init configuration */
+
+ {
+ ngx_poll_add_event, /* add an event */
+ ngx_poll_del_event, /* delete an event */
+ ngx_poll_add_event, /* enable an event */
+ ngx_poll_del_event, /* disable an event */
+ NULL, /* add an connection */
+ NULL, /* delete an connection */
+ NULL, /* trigger a notify */
+ ngx_poll_process_events, /* process the events */
+ ngx_poll_init, /* init the events */
+ ngx_poll_done /* done the events */
+ }
+
+};
+
+ngx_module_t ngx_poll_module = {
+ NGX_MODULE_V1,
+ &ngx_poll_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_EVENT_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+
+static ngx_int_t
+ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
+{
+ struct pollfd *list;
+ ngx_connection_t **index;
+
+ if (event_list == NULL) {
+ nevents = 0;
+ }
+
+ if (ngx_process >= NGX_PROCESS_WORKER
+ || cycle->old_cycle == NULL
+ || cycle->old_cycle->connection_n < cycle->connection_n)
+ {
+ list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n,
+ cycle->log);
+ if (list == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (event_list) {
+ ngx_memcpy(list, event_list, sizeof(struct pollfd) * nevents);
+ ngx_free(event_list);
+ }
+
+ event_list = list;
+
+ index = ngx_alloc(sizeof(ngx_connection_t *) * cycle->connection_n,
+ cycle->log);
+ if (index == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (event_index) {
+ ngx_memcpy(index, event_index,
+ sizeof(ngx_connection_t *) * nevents);
+ ngx_free(event_index);
+ }
+
+ event_index = index;
+ }
+
+ ngx_io = ngx_os_io;
+
+ ngx_event_actions = ngx_poll_module_ctx.actions;
+
+ ngx_event_flags = NGX_USE_LEVEL_EVENT;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_poll_done(ngx_cycle_t *cycle)
+{
+ ngx_free(event_list);
+ ngx_free(event_index);
+
+ event_list = NULL;
+ event_index = NULL;
+}
+
+
+static ngx_int_t
+ngx_poll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ev->active = 1;
+
+ if (ev->index != NGX_INVALID_INDEX) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "poll event fd:%d ev:%i is already set", c->fd, event);
+ return NGX_OK;
+ }
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+#if (NGX_READ_EVENT != POLLIN)
+ event = POLLIN;
+#endif
+
+ } else {
+ e = c->read;
+#if (NGX_WRITE_EVENT != POLLOUT)
+ event = POLLOUT;
+#endif
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll add event: fd:%d ev:%i", c->fd, event);
+
+ if (e == NULL || e->index == NGX_INVALID_INDEX) {
+
+ event_list[nevents].fd = c->fd;
+ event_list[nevents].events = (short) event;
+ event_list[nevents].revents = 0;
+
+ event_index[nevents] = c;
+
+ ev->index = nevents;
+ nevents++;
+
+ } else {
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll add index: %i", e->index);
+
+ event_list[e->index].events |= (short) event;
+ ev->index = e->index;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_poll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
+{
+ ngx_event_t *e;
+ ngx_connection_t *c;
+
+ c = ev->data;
+
+ ev->active = 0;
+
+ if (ev->index == NGX_INVALID_INDEX) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "poll event fd:%d ev:%i is already deleted",
+ c->fd, event);
+ return NGX_OK;
+ }
+
+ if (event == NGX_READ_EVENT) {
+ e = c->write;
+#if (NGX_READ_EVENT != POLLIN)
+ event = POLLIN;
+#endif
+
+ } else {
+ e = c->read;
+#if (NGX_WRITE_EVENT != POLLOUT)
+ event = POLLOUT;
+#endif
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll del event: fd:%d ev:%i", c->fd, event);
+
+ if (e == NULL || e->index == NGX_INVALID_INDEX) {
+ nevents--;
+
+ if (ev->index < nevents) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "index: copy event %ui to %i", nevents, ev->index);
+
+ event_list[ev->index] = event_list[nevents];
+ event_index[ev->index] = event_index[nevents];
+
+ c = event_index[ev->index];
+
+ if (c->fd == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
+ "unexpected last event");
+
+ } else {
+ if (c->read->index == nevents) {
+ c->read->index = ev->index;
+ }
+
+ if (c->write->index == nevents) {
+ c->write->index = ev->index;
+ }
+ }
+ }
+
+ } else {
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ev->log, 0,
+ "poll del index: %i", e->index);
+
+ event_list[e->index].events &= (short) ~event;
+ }
+
+ ev->index = NGX_INVALID_INDEX;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
+{
+ int ready, revents;
+ ngx_err_t err;
+ ngx_uint_t i, found;
+ ngx_event_t *ev;
+ ngx_queue_t *queue;
+ ngx_connection_t *c;
+
+ /* NGX_TIMER_INFINITE == INFTIM */
+
+#if (NGX_DEBUG0)
+ if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
+ for (i = 0; i < nevents; i++) {
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll: %ui: fd:%d ev:%04Xd",
+ i, event_list[i].fd, event_list[i].events);
+ }
+ }
+#endif
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer);
+
+ ready = WSAPoll(event_list, (u_int) nevents, (int) timer);
+
+ err = (ready == -1) ? ngx_errno : 0;
+
+ if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
+ ngx_time_update();
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll ready %d of %ui", ready, nevents);
+
+ if (err) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WSAPoll() failed");
+ return NGX_ERROR;
+ }
+
+ if (ready == 0) {
+ if (timer != NGX_TIMER_INFINITE) {
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "WSAPoll() returned no events without timeout");
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < nevents && ready; i++) {
+
+ revents = event_list[i].revents;
+
+#if 1
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
+ i, event_list[i].fd, event_list[i].events, revents);
+#else
+ if (revents) {
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "poll: %ui: fd:%d ev:%04Xd rev:%04Xd",
+ i, event_list[i].fd, event_list[i].events, revents);
+ }
+#endif
+
+ if (revents & POLLNVAL) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "poll() error fd:%d ev:%04Xd rev:%04Xd",
+ event_list[i].fd, event_list[i].events, revents);
+ }
+
+ if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "strange poll() events fd:%d ev:%04Xd rev:%04Xd",
+ event_list[i].fd, event_list[i].events, revents);
+ }
+
+ if (event_list[i].fd == (ngx_socket_t) -1) {
+ /*
+ * the disabled event, a workaround for our possible bug,
+ * see the comment below
+ */
+ continue;
+ }
+
+ c = event_index[i];
+
+ if (c->fd == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
+
+ /*
+ * it is certainly our fault and it should be investigated,
+ * in the meantime we disable this event to avoid a CPU spinning
+ */
+
+ if (i == nevents - 1) {
+ nevents--;
+ } else {
+ event_list[i].fd = (ngx_socket_t) -1;
+ }
+
+ continue;
+ }
+
+ if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
+
+ /*
+ * if the error events were returned, add POLLIN and POLLOUT
+ * to handle the events at least in one active handler
+ */
+
+ revents |= POLLIN|POLLOUT;
+ }
+
+ found = 0;
+
+ if ((revents & POLLIN) && c->read->active) {
+ found = 1;
+
+ ev = c->read;
+ ev->ready = 1;
+
+ queue = ev->accept ? &ngx_posted_accept_events
+ : &ngx_posted_events;
+
+ ngx_post_event(ev, queue);
+ }
+
+ if ((revents & POLLOUT) && c->write->active) {
+ found = 1;
+
+ ev = c->write;
+ ev->ready = 1;
+
+ ngx_post_event(ev, &ngx_posted_events);
+ }
+
+ if (found) {
+ ready--;
+ continue;
+ }
+ }
+
+ if (ready != 0) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
+ }
+
+ return NGX_OK;
+}
+
+
+static char *
+ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf)
+{
+ ngx_event_conf_t *ecf;
+
+ ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);
+
+ if (ecf->use != ngx_poll_module.ctx_index) {
+ return NGX_CONF_OK;
+ }
+
+#if (NGX_LOAD_WSAPOLL)
+
+ if (!ngx_have_wsapoll) {
+ ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
+ "poll is not available on this platform");
+ return NGX_CONF_ERROR;
+ }
+
+#endif
+
+ return NGX_CONF_OK;
+}
diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c
index ba98f07..c464805 100644
--- a/src/event/modules/ngx_win32_select_module.c
+++ b/src/event/modules/ngx_win32_select_module.c
@@ -26,6 +26,7 @@
static fd_set master_write_fd_set;
static fd_set work_read_fd_set;
static fd_set work_write_fd_set;
+static fd_set work_except_fd_set;
static ngx_uint_t max_read;
static ngx_uint_t max_write;
@@ -253,9 +254,11 @@
work_read_fd_set = master_read_fd_set;
work_write_fd_set = master_write_fd_set;
+ work_except_fd_set = master_write_fd_set;
if (max_read || max_write) {
- ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
+ ready = select(0, &work_read_fd_set, &work_write_fd_set,
+ &work_except_fd_set, tp);
} else {
@@ -308,14 +311,20 @@
if (ev->write) {
if (FD_ISSET(c->fd, &work_write_fd_set)) {
- found = 1;
+ found++;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"select write %d", c->fd);
}
+ if (FD_ISSET(c->fd, &work_except_fd_set)) {
+ found++;
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+ "select except %d", c->fd);
+ }
+
} else {
if (FD_ISSET(c->fd, &work_read_fd_set)) {
- found = 1;
+ found++;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"select read %d", c->fd);
}
@@ -329,7 +338,7 @@
ngx_post_event(ev, queue);
- nready++;
+ nready += found;
}
}
diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h
index 7253ebb..d3b2378 100644
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -63,6 +63,7 @@
unsigned cached:1;
unsigned transparent:1;
unsigned so_keepalive:1;
+ unsigned down:1;
/* ngx_connection_log_error_e */
unsigned log_error:2;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 958483d..b42b145 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -18,6 +18,10 @@
} ngx_openssl_conf_t;
+static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err,
+ ngx_str_t *cert, STACK_OF(X509) **chain);
+static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err,
+ ngx_str_t *key, ngx_array_t *passwords);
static int ngx_ssl_password_callback(char *buf, int size, int rwflag,
void *userdata);
static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
@@ -50,7 +54,7 @@
static void ngx_ssl_clear_error(ngx_log_t *log);
static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl,
- ngx_str_t *sess_ctx);
+ ngx_str_t *sess_ctx, ngx_array_t *certificates);
static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
ngx_ssl_session_t *sess);
static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
@@ -68,6 +72,7 @@
static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
HMAC_CTX *hctx, int enc);
+static void ngx_ssl_session_ticket_keys_cleanup(void *data);
#endif
#ifndef X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT
@@ -406,16 +411,209 @@
ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
ngx_str_t *key, ngx_array_t *passwords)
{
- BIO *bio;
- X509 *x509;
- u_long n;
- ngx_str_t *pwd;
- ngx_uint_t tries;
+ char *err;
+ X509 *x509;
+ EVP_PKEY *pkey;
+ STACK_OF(X509) *chain;
- if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
+ x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain);
+ if (x509 == NULL) {
+ if (err != NULL) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "cannot load certificate \"%s\": %s",
+ cert->data, err);
+ }
+
return NGX_ERROR;
}
+ if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_use_certificate(\"%s\") failed", cert->data);
+ X509_free(x509);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+ if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
+ X509_free(x509);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+ if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index,
+ SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index))
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
+ X509_free(x509);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ X509_free(x509);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+ /*
+ * Note that x509 is not freed here, but will be instead freed in
+ * ngx_ssl_cleanup_ctx(). This is because we need to preserve all
+ * certificates to be able to iterate all of them through exdata
+ * (ngx_ssl_certificate_index, ngx_ssl_next_certificate_index),
+ * while OpenSSL can free a certificate if it is replaced with another
+ * certificate of the same type.
+ */
+
+#ifdef SSL_CTX_set0_chain
+
+ if (SSL_CTX_set0_chain(ssl->ctx, chain) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set0_chain(\"%s\") failed", cert->data);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+#else
+ {
+ int n;
+
+ /* SSL_CTX_set0_chain() is only available in OpenSSL 1.0.2+ */
+
+ n = sk_X509_num(chain);
+
+ while (n--) {
+ x509 = sk_X509_shift(chain);
+
+ if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
+ cert->data);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+ }
+
+ sk_X509_free(chain);
+ }
+#endif
+
+ pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords);
+ if (pkey == NULL) {
+ if (err != NULL) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "cannot load certificate key \"%s\": %s",
+ key->data, err);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_use_PrivateKey(\"%s\") failed", key->data);
+ EVP_PKEY_free(pkey);
+ return NGX_ERROR;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
+ ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords)
+{
+ char *err;
+ X509 *x509;
+ EVP_PKEY *pkey;
+ STACK_OF(X509) *chain;
+
+ x509 = ngx_ssl_load_certificate(pool, &err, cert, &chain);
+ if (x509 == NULL) {
+ if (err != NULL) {
+ ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
+ "cannot load certificate \"%s\": %s",
+ cert->data, err);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (SSL_use_certificate(c->ssl->connection, x509) == 0) {
+ ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
+ "SSL_use_certificate(\"%s\") failed", cert->data);
+ X509_free(x509);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+ X509_free(x509);
+
+#ifdef SSL_set0_chain
+
+ /*
+ * SSL_set0_chain() is only available in OpenSSL 1.0.2+,
+ * but this function is only called via certificate callback,
+ * which is only available in OpenSSL 1.0.2+ as well
+ */
+
+ if (SSL_set0_chain(c->ssl->connection, chain) == 0) {
+ ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
+ "SSL_set0_chain(\"%s\") failed", cert->data);
+ sk_X509_pop_free(chain, X509_free);
+ return NGX_ERROR;
+ }
+
+#endif
+
+ pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords);
+ if (pkey == NULL) {
+ if (err != NULL) {
+ ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
+ "cannot load certificate key \"%s\": %s",
+ key->data, err);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (SSL_use_PrivateKey(c->ssl->connection, pkey) == 0) {
+ ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
+ "SSL_use_PrivateKey(\"%s\") failed", key->data);
+ EVP_PKEY_free(pkey);
+ return NGX_ERROR;
+ }
+
+ EVP_PKEY_free(pkey);
+
+ return NGX_OK;
+}
+
+
+static X509 *
+ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert,
+ STACK_OF(X509) **chain)
+{
+ BIO *bio;
+ X509 *x509, *temp;
+ u_long n;
+
+ if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, cert)
+ != NGX_OK)
+ {
+ *err = NULL;
+ return NULL;
+ }
+
/*
* we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
* allow to access certificate later from SSL_CTX, so we reimplement
@@ -424,62 +622,33 @@
bio = BIO_new_file((char *) cert->data, "r");
if (bio == NULL) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "BIO_new_file(\"%s\") failed", cert->data);
- return NGX_ERROR;
+ *err = "BIO_new_file() failed";
+ return NULL;
}
+ /* certificate itself */
+
x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
if (x509 == NULL) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);
+ *err = "PEM_read_bio_X509_AUX() failed";
BIO_free(bio);
- return NGX_ERROR;
+ return NULL;
}
- if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_use_certificate(\"%s\") failed", cert->data);
+ /* rest of the chain */
+
+ *chain = sk_X509_new_null();
+ if (*chain == NULL) {
+ *err = "sk_X509_new_null() failed";
+ BIO_free(bio);
X509_free(x509);
- BIO_free(bio);
- return NGX_ERROR;
+ return NULL;
}
- if (X509_set_ex_data(x509, ngx_ssl_certificate_name_index, cert->data)
- == 0)
- {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
- X509_free(x509);
- BIO_free(bio);
- return NGX_ERROR;
- }
-
- if (X509_set_ex_data(x509, ngx_ssl_next_certificate_index,
- SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index))
- == 0)
- {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_set_ex_data() failed");
- X509_free(x509);
- BIO_free(bio);
- return NGX_ERROR;
- }
-
- if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
- == 0)
- {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_set_ex_data() failed");
- X509_free(x509);
- BIO_free(bio);
- return NGX_ERROR;
- }
-
- /* read rest of the chain */
-
for ( ;; ) {
- x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
- if (x509 == NULL) {
+ temp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+ if (temp == NULL) {
n = ERR_peek_last_error();
if (ERR_GET_LIB(n) == ERR_LIB_PEM
@@ -492,43 +661,38 @@
/* some real error */
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "PEM_read_bio_X509(\"%s\") failed", cert->data);
+ *err = "PEM_read_bio_X509() failed";
BIO_free(bio);
- return NGX_ERROR;
- }
-
-#ifdef SSL_CTRL_CHAIN_CERT
-
- /*
- * SSL_CTX_add0_chain_cert() is needed to add chain to
- * a particular certificate when multiple certificates are used;
- * only available in OpenSSL 1.0.2+
- */
-
- if (SSL_CTX_add0_chain_cert(ssl->ctx, x509) == 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_add0_chain_cert(\"%s\") failed",
- cert->data);
X509_free(x509);
- BIO_free(bio);
- return NGX_ERROR;
+ sk_X509_pop_free(*chain, X509_free);
+ return NULL;
}
-#else
- if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
- cert->data);
- X509_free(x509);
+ if (sk_X509_push(*chain, temp) == 0) {
+ *err = "sk_X509_push() failed";
BIO_free(bio);
- return NGX_ERROR;
+ X509_free(x509);
+ sk_X509_pop_free(*chain, X509_free);
+ return NULL;
}
-#endif
}
BIO_free(bio);
+ return x509;
+}
+
+
+static EVP_PKEY *
+ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err,
+ ngx_str_t *key, ngx_array_t *passwords)
+{
+ BIO *bio;
+ EVP_PKEY *pkey;
+ ngx_str_t *pwd;
+ ngx_uint_t tries;
+ pem_password_cb *cb;
+
if (ngx_strncmp(key->data, "engine:", sizeof("engine:") - 1) == 0) {
#ifndef OPENSSL_NO_ENGINE
@@ -541,9 +705,8 @@
last = (u_char *) ngx_strchr(p, ':');
if (last == NULL) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid syntax in \"%V\"", key);
- return NGX_ERROR;
+ *err = "invalid syntax";
+ return NULL;
}
*last = '\0';
@@ -551,9 +714,8 @@
engine = ENGINE_by_id((char *) p);
if (engine == NULL) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "ENGINE_by_id(\"%s\") failed", p);
- return NGX_ERROR;
+ *err = "ENGINE_by_id() failed";
+ return NULL;
}
*last++ = ':';
@@ -561,76 +723,69 @@
pkey = ENGINE_load_private_key(engine, (char *) last, 0, 0);
if (pkey == NULL) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "ENGINE_load_private_key(\"%s\") failed", last);
+ *err = "ENGINE_load_private_key() failed";
ENGINE_free(engine);
- return NGX_ERROR;
+ return NULL;
}
ENGINE_free(engine);
- if (SSL_CTX_use_PrivateKey(ssl->ctx, pkey) == 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_use_PrivateKey(\"%s\") failed", last);
- EVP_PKEY_free(pkey);
- return NGX_ERROR;
- }
-
- EVP_PKEY_free(pkey);
-
- return NGX_OK;
+ return pkey;
#else
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "loading \"engine:...\" certificate keys "
- "is not supported");
- return NGX_ERROR;
+ *err = "loading \"engine:...\" certificate keys is not supported";
+ return NULL;
#endif
}
- if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
- return NGX_ERROR;
+ if (ngx_get_full_name(pool, (ngx_str_t *) &ngx_cycle->conf_prefix, key)
+ != NGX_OK)
+ {
+ *err = NULL;
+ return NULL;
+ }
+
+ bio = BIO_new_file((char *) key->data, "r");
+ if (bio == NULL) {
+ *err = "BIO_new_file() failed";
+ return NULL;
}
if (passwords) {
tries = passwords->nelts;
pwd = passwords->elts;
-
- SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);
- SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);
+ cb = ngx_ssl_password_callback;
} else {
tries = 1;
-#if (NGX_SUPPRESS_WARN)
pwd = NULL;
-#endif
+ cb = NULL;
}
for ( ;; ) {
- if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
- SSL_FILETYPE_PEM)
- != 0)
- {
+ pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd);
+ if (pkey != NULL) {
break;
}
- if (--tries) {
+ if (tries-- > 1) {
ERR_clear_error();
- SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
+ (void) BIO_reset(bio);
+ pwd++;
continue;
}
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
- return NGX_ERROR;
+ *err = "PEM_read_bio_PrivateKey() failed";
+ BIO_free(bio);
+ return NULL;
}
- SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
+ BIO_free(bio);
- return NGX_OK;
+ return pkey;
}
@@ -645,6 +800,10 @@
return 0;
}
+ if (pwd == NULL) {
+ return 0;
+ }
+
if (pwd->len > (size_t) size) {
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
"password is truncated to %d bytes", size);
@@ -969,10 +1128,13 @@
return NULL;
}
- cln = ngx_pool_cleanup_add(cf->temp_pool, 0);
passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t));
+ if (passwords == NULL) {
+ return NULL;
+ }
- if (cln == NULL || passwords == NULL) {
+ cln = ngx_pool_cleanup_add(cf->temp_pool, 0);
+ if (cln == NULL) {
return NULL;
}
@@ -1080,6 +1242,69 @@
}
+ngx_array_t *
+ngx_ssl_preserve_passwords(ngx_conf_t *cf, ngx_array_t *passwords)
+{
+ ngx_str_t *opwd, *pwd;
+ ngx_uint_t i;
+ ngx_array_t *pwds;
+ ngx_pool_cleanup_t *cln;
+ static ngx_array_t empty_passwords;
+
+ if (passwords == NULL) {
+
+ /*
+ * If there are no passwords, an empty array is used
+ * to make sure OpenSSL's default password callback
+ * won't block on reading from stdin.
+ */
+
+ return &empty_passwords;
+ }
+
+ /*
+ * Passwords are normally allocated from the temporary pool
+ * and cleared after parsing configuration. To be used at
+ * runtime they have to be copied to the configuration pool.
+ */
+
+ pwds = ngx_array_create(cf->pool, passwords->nelts, sizeof(ngx_str_t));
+ if (pwds == NULL) {
+ return NULL;
+ }
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NULL;
+ }
+
+ cln->handler = ngx_ssl_passwords_cleanup;
+ cln->data = pwds;
+
+ opwd = passwords->elts;
+
+ for (i = 0; i < passwords->nelts; i++) {
+
+ pwd = ngx_array_push(pwds);
+ if (pwd == NULL) {
+ return NULL;
+ }
+
+ pwd->len = opwd[i].len;
+ pwd->data = ngx_pnalloc(cf->pool, pwd->len);
+
+ if (pwd->data == NULL) {
+ pwds->nelts--;
+ return NULL;
+ }
+
+ ngx_memcpy(pwd->data, opwd[i].data, opwd[i].len);
+ }
+
+ return pwds;
+}
+
+
static void
ngx_ssl_passwords_cleanup(void *data)
{
@@ -2686,6 +2911,9 @@
#ifdef SSL_R_INAPPROPRIATE_FALLBACK
|| n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */
#endif
+#ifdef SSL_R_CERT_CB_ERROR
+ || n == SSL_R_CERT_CB_ERROR /* 377 */
+#endif
#ifdef SSL_R_VERSION_TOO_LOW
|| n == SSL_R_VERSION_TOO_LOW /* 396 */
#endif
@@ -2765,53 +2993,60 @@
p = ngx_vslprintf(errstr, last - 1, fmt, args);
va_end(args);
- p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
+ if (ERR_peek_error()) {
+ p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
- for ( ;; ) {
+ for ( ;; ) {
- n = ERR_peek_error_line_data(NULL, NULL, &data, &flags);
+ n = ERR_peek_error_line_data(NULL, NULL, &data, &flags);
- if (n == 0) {
- break;
+ if (n == 0) {
+ break;
+ }
+
+ /* ERR_error_string_n() requires at least one byte */
+
+ if (p >= last - 1) {
+ goto next;
+ }
+
+ *p++ = ' ';
+
+ ERR_error_string_n(n, (char *) p, last - p);
+
+ while (p < last && *p) {
+ p++;
+ }
+
+ if (p < last && *data && (flags & ERR_TXT_STRING)) {
+ *p++ = ':';
+ p = ngx_cpystrn(p, (u_char *) data, last - p);
+ }
+
+ next:
+
+ (void) ERR_get_error();
}
- /* ERR_error_string_n() requires at least one byte */
-
- if (p >= last - 1) {
- goto next;
+ if (p < last) {
+ *p++ = ')';
}
-
- *p++ = ' ';
-
- ERR_error_string_n(n, (char *) p, last - p);
-
- while (p < last && *p) {
- p++;
- }
-
- if (p < last && *data && (flags & ERR_TXT_STRING)) {
- *p++ = ':';
- p = ngx_cpystrn(p, (u_char *) data, last - p);
- }
-
- next:
-
- (void) ERR_get_error();
}
- ngx_log_error(level, log, err, "%*s)", p - errstr, errstr);
+ ngx_log_error(level, log, err, "%*s", p - errstr, errstr);
}
ngx_int_t
ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
- ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
+ ngx_array_t *certificates, ssize_t builtin_session_cache,
+ ngx_shm_zone_t *shm_zone, time_t timeout)
{
long cache_mode;
SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
- if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) {
+ if (ngx_ssl_session_id_context(ssl, sess_ctx, certificates) != NGX_OK) {
return NGX_ERROR;
}
@@ -2877,11 +3112,14 @@
static ngx_int_t
-ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
+ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
+ ngx_array_t *certificates)
{
int n, i;
X509 *cert;
X509_NAME *name;
+ ngx_str_t *certs;
+ ngx_uint_t k;
EVP_MD_CTX *md;
unsigned int len;
STACK_OF(X509_NAME) *list;
@@ -2926,6 +3164,24 @@
}
}
+ if (SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index) == NULL) {
+
+ /*
+ * If certificates are loaded dynamically, we use certificate
+ * names as specified in the configuration (with variables).
+ */
+
+ certs = certificates->elts;
+ for (k = 0; k < certificates->nelts; k++) {
+
+ if (EVP_DigestUpdate(md, certs[k].data, certs[k].len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "EVP_DigestUpdate() failed");
+ goto failed;
+ }
+ }
+ }
+
list = SSL_CTX_get_client_CA_list(ssl->ctx);
if (list != NULL) {
@@ -2950,7 +3206,7 @@
if (EVP_DigestFinal_ex(md, buf, &len) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "EVP_DigestUpdate() failed");
+ "EVP_DigestFinal_ex() failed");
goto failed;
}
@@ -3481,6 +3737,7 @@
ngx_uint_t i;
ngx_array_t *keys;
ngx_file_info_t fi;
+ ngx_pool_cleanup_t *cln;
ngx_ssl_session_ticket_key_t *key;
if (paths == NULL) {
@@ -3493,6 +3750,14 @@
return NGX_ERROR;
}
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ cln->handler = ngx_ssl_session_ticket_keys_cleanup;
+ cln->data = keys;
+
path = paths->elts;
for (i = 0; i < paths->nelts; i++) {
@@ -3564,6 +3829,8 @@
ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
ngx_close_file_n " \"%V\" failed", &file.name);
}
+
+ ngx_explicit_memzero(&buf, 80);
}
if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys)
@@ -3594,6 +3861,8 @@
ngx_close_file_n " \"%V\" failed", &file.name);
}
+ ngx_explicit_memzero(&buf, 80);
+
return NGX_ERROR;
}
@@ -3722,6 +3991,16 @@
}
}
+
+static void
+ngx_ssl_session_ticket_keys_cleanup(void *data)
+{
+ ngx_array_t *keys = data;
+
+ ngx_explicit_memzero(keys->elts,
+ keys->nelts * sizeof(ngx_ssl_session_ticket_key_t));
+}
+
#else
ngx_int_t
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 2495e48..f34ccf9 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -161,10 +161,14 @@
ngx_int_t ngx_ssl_init(ngx_log_t *log);
ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
+
ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords);
ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
+ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool,
+ ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
+
ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers,
ngx_uint_t prefer_server_ciphers);
ngx_int_t ngx_ssl_alpn_protos(ngx_conf_t *cf, ngx_ssl_t *ssl,
@@ -181,6 +185,8 @@
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
int key_length);
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
+ngx_array_t *ngx_ssl_preserve_passwords(ngx_conf_t *cf,
+ ngx_array_t *passwords);
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl,
@@ -188,7 +194,8 @@
ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_uint_t enable);
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
- ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout);
+ ngx_array_t *certificates, ssize_t builtin_session_cache,
+ ngx_shm_zone_t *shm_zone, time_t timeout);
ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_array_t *paths);
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
diff --git a/src/event/ngx_event_udp.c b/src/event/ngx_event_udp.c
index 65eb22f..5572830 100644
--- a/src/event/ngx_event_udp.c
+++ b/src/event/ngx_event_udp.c
@@ -256,7 +256,9 @@
rev = c->read;
c->udp->buffer = &buf;
+
rev->ready = 1;
+ rev->active = 0;
rev->handler(rev);
@@ -265,6 +267,7 @@
}
rev->ready = 0;
+ rev->active = 1;
goto next;
}
@@ -343,6 +346,7 @@
rev = c->read;
wev = c->write;
+ rev->active = 1;
wev->ready = 1;
rev->log = log;
@@ -453,7 +457,9 @@
ngx_memcpy(buf, b->pos, n);
c->udp->buffer = NULL;
+
c->read->ready = 0;
+ c->read->active = 1;
return n;
}
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index dfff2b8..c184606 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -39,6 +39,9 @@
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child);
+static ngx_int_t ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
+ ngx_http_ssl_srv_conf_t *conf);
+
static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -548,6 +551,7 @@
* set by ngx_pcalloc():
*
* sscf->protocols = 0;
+ * sscf->certificate_values = NULL;
* sscf->dhparam = { 0, NULL };
* sscf->ecdh_curve = { 0, NULL };
* sscf->client_certificate = { 0, NULL };
@@ -740,13 +744,38 @@
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = &conf->ssl;
- if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
- conf->certificate_keys, conf->passwords)
- != NGX_OK)
- {
+ if (ngx_http_ssl_compile_certificates(cf, conf) != NGX_OK) {
return NGX_CONF_ERROR;
}
+ if (conf->certificate_values) {
+
+#ifdef SSL_R_CERT_CB_ERROR
+
+ /* install callback to lookup certificates */
+
+ SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_http_ssl_certificate, conf);
+
+#else
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "variables in "
+ "\"ssl_certificate\" and \"ssl_certificate_key\" "
+ "directives are not supported on this platform");
+ return NGX_CONF_ERROR;
+#endif
+
+ } else {
+
+ /* configure certificates */
+
+ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
+ conf->certificate_keys, conf->passwords)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
@@ -801,7 +830,7 @@
}
if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx,
- conf->builtin_session_cache,
+ conf->certificates, conf->builtin_session_cache,
conf->shm_zone, conf->session_timeout)
!= NGX_OK)
{
@@ -844,6 +873,90 @@
}
+static ngx_int_t
+ngx_http_ssl_compile_certificates(ngx_conf_t *cf,
+ ngx_http_ssl_srv_conf_t *conf)
+{
+ ngx_str_t *cert, *key;
+ ngx_uint_t i, nelts;
+ ngx_http_complex_value_t *cv;
+ ngx_http_compile_complex_value_t ccv;
+
+ cert = conf->certificates->elts;
+ key = conf->certificate_keys->elts;
+ nelts = conf->certificates->nelts;
+
+ for (i = 0; i < nelts; i++) {
+
+ if (ngx_http_script_variables_count(&cert[i])) {
+ goto found;
+ }
+
+ if (ngx_http_script_variables_count(&key[i])) {
+ goto found;
+ }
+ }
+
+ return NGX_OK;
+
+found:
+
+ conf->certificate_values = ngx_array_create(cf->pool, nelts,
+ sizeof(ngx_http_complex_value_t));
+ if (conf->certificate_values == NULL) {
+ return NGX_ERROR;
+ }
+
+ conf->certificate_key_values = ngx_array_create(cf->pool, nelts,
+ sizeof(ngx_http_complex_value_t));
+ if (conf->certificate_key_values == NULL) {
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < nelts; i++) {
+
+ cv = ngx_array_push(conf->certificate_values);
+ if (cv == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &cert[i];
+ ccv.complex_value = cv;
+ ccv.zero = 1;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ cv = ngx_array_push(conf->certificate_key_values);
+ if (cv == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &key[i];
+ ccv.complex_value = cv;
+ ccv.zero = 1;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords);
+ if (conf->passwords == NULL) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
static char *
ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
index fb3219b..26fdccf 100644
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -36,6 +36,9 @@
ngx_array_t *certificates;
ngx_array_t *certificate_keys;
+ ngx_array_t *certificate_values;
+ ngx_array_t *certificate_key_values;
+
ngx_str_t dhparam;
ngx_str_t ecdh_curve;
ngx_str_t client_certificate;
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index f6bece5..7758c0a 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -96,6 +96,10 @@
#endif
int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
#endif
+#if (NGX_HTTP_SSL && defined SSL_R_CERT_CB_ERROR)
+int ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
+#endif
+
ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b);
ngx_int_t ngx_http_parse_uri(ngx_http_request_t *r);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index eb5ead5..3762aef 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -11,6 +11,7 @@
static void ngx_http_wait_request_handler(ngx_event_t *ev);
+static ngx_http_request_t *ngx_http_alloc_request(ngx_connection_t *c);
static void ngx_http_process_request_line(ngx_event_t *rev);
static void ngx_http_process_request_headers(ngx_event_t *rev);
static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
@@ -503,17 +504,45 @@
ngx_http_request_t *
ngx_http_create_request(ngx_connection_t *c)
{
+ ngx_http_request_t *r;
+ ngx_http_log_ctx_t *ctx;
+ ngx_http_core_loc_conf_t *clcf;
+
+ r = ngx_http_alloc_request(c);
+ if (r == NULL) {
+ return NULL;
+ }
+
+ c->requests++;
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ ngx_set_connection_log(c, clcf->error_log);
+
+ ctx = c->log->data;
+ ctx->request = r;
+ ctx->current_request = r;
+
+#if (NGX_STAT_STUB)
+ (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
+ r->stat_reading = 1;
+ (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
+#endif
+
+ return r;
+}
+
+
+static ngx_http_request_t *
+ngx_http_alloc_request(ngx_connection_t *c)
+{
ngx_pool_t *pool;
ngx_time_t *tp;
ngx_http_request_t *r;
- ngx_http_log_ctx_t *ctx;
ngx_http_connection_t *hc;
ngx_http_core_srv_conf_t *cscf;
- ngx_http_core_loc_conf_t *clcf;
ngx_http_core_main_conf_t *cmcf;
- c->requests++;
-
hc = c->data;
cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
@@ -541,10 +570,6 @@
r->read_event_handler = ngx_http_block_reading;
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
- ngx_set_connection_log(r->connection, clcf->error_log);
-
r->header_in = hc->busy ? hc->busy->buf : c->buffer;
if (ngx_list_init(&r->headers_out.headers, r->pool, 20,
@@ -604,17 +629,8 @@
r->http_state = NGX_HTTP_READING_REQUEST_STATE;
- ctx = c->log->data;
- ctx->request = r;
- ctx->current_request = r;
r->log_handler = ngx_http_log_error_handler;
-#if (NGX_STAT_STUB)
- (void) ngx_atomic_fetch_add(ngx_stat_reading, 1);
- r->stat_reading = 1;
- (void) ngx_atomic_fetch_add(ngx_stat_requests, 1);
-#endif
-
return r;
}
@@ -833,6 +849,7 @@
ngx_http_close_connection(c);
}
+
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
#if defined(OPENSSL_IS_BORINGSSL)
@@ -1085,6 +1102,75 @@
#endif
+
+#ifdef SSL_R_CERT_CB_ERROR
+
+int
+ngx_http_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
+{
+ ngx_str_t cert, key;
+ ngx_uint_t i, nelts;
+ ngx_connection_t *c;
+ ngx_http_request_t *r;
+ ngx_http_ssl_srv_conf_t *sscf;
+ ngx_http_complex_value_t *certs, *keys;
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ if (c->ssl->handshaked) {
+ return 0;
+ }
+
+ r = ngx_http_alloc_request(c);
+ if (r == NULL) {
+ return 0;
+ }
+
+ r->logged = 1;
+
+ sscf = arg;
+
+ nelts = sscf->certificate_values->nelts;
+ certs = sscf->certificate_values->elts;
+ keys = sscf->certificate_key_values->elts;
+
+ for (i = 0; i < nelts; i++) {
+
+ if (ngx_http_complex_value(r, &certs[i], &cert) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl cert: \"%s\"", cert.data);
+
+ if (ngx_http_complex_value(r, &keys[i], &key) != NGX_OK) {
+ goto failed;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ "ssl key: \"%s\"", key.data);
+
+ if (ngx_ssl_connection_certificate(c, r->pool, &cert, &key,
+ sscf->passwords)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+ }
+
+ ngx_http_free_request(r, 0);
+ c->destroyed = 0;
+ return 1;
+
+failed:
+
+ ngx_http_free_request(r, 0);
+ c->destroyed = 0;
+ return 0;
+}
+
+#endif
+
#endif
@@ -3684,9 +3770,11 @@
r->headers_out.status = rc;
}
- log->action = "logging request";
+ if (!r->logged) {
+ log->action = "logging request";
- ngx_http_log_request(r);
+ ngx_http_log_request(r);
+ }
log->action = "closing request";
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 1a87735..4153889 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -271,6 +271,34 @@
}
+ngx_int_t
+ngx_http_test_required_predicates(ngx_http_request_t *r,
+ ngx_array_t *predicates)
+{
+ ngx_str_t val;
+ ngx_uint_t i;
+ ngx_http_complex_value_t *cv;
+
+ if (predicates == NULL) {
+ return NGX_OK;
+ }
+
+ cv = predicates->elts;
+
+ for (i = 0; i < predicates->nelts; i++) {
+ if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (val.len == 0 || (val.len == 1 && val.data[0] == '0')) {
+ return NGX_DECLINED;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
char *
ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h
index a5116d7..25bb6d7 100644
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -214,6 +214,8 @@
ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r,
ngx_array_t *predicates);
+ngx_int_t ngx_http_test_required_predicates(ngx_http_request_t *r,
+ ngx_array_t *predicates);
char *ngx_http_set_predicate_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 7356bd1..fea4ea1 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -850,7 +850,7 @@
ngx_http_file_cache_create_key(r);
- if (r->cache->header_start + 256 >= u->conf->buffer_size) {
+ if (r->cache->header_start + 256 > u->conf->buffer_size) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"%V_buffer_size %uz is not enough for cache key, "
"it should be increased to at least %uz",
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index 4509597..10e982e 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -435,7 +435,7 @@
}
if (ngx_ssl_session_cache(&conf->ssl, &ngx_mail_ssl_sess_id_ctx,
- conf->builtin_session_cache,
+ conf->certificates, conf->builtin_session_cache,
conf->shm_zone, conf->session_timeout)
!= NGX_OK)
{
diff --git a/src/os/unix/ngx_file_aio_read.c b/src/os/unix/ngx_file_aio_read.c
index aedc3c9..bb60ee8 100644
--- a/src/os/unix/ngx_file_aio_read.c
+++ b/src/os/unix/ngx_file_aio_read.c
@@ -110,7 +110,7 @@
#if (NGX_HAVE_KQUEUE)
aio->aiocb.aio_sigevent.sigev_notify_kqueue = ngx_kqueue;
aio->aiocb.aio_sigevent.sigev_notify = SIGEV_KEVENT;
- aio->aiocb.aio_sigevent.sigev_value.sigval_ptr = ev;
+ aio->aiocb.aio_sigevent.sigev_value.sival_ptr = ev;
#endif
ev->handler = ngx_file_aio_event_handler;
diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h
index b7da48c..c641108 100644
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -89,8 +89,14 @@
#if (NGX_HAVE_FILE_AIO)
+
#include <aio.h>
typedef struct aiocb ngx_aiocb_t;
+
+#if (__FreeBSD_version < 700005 && !defined __DragonFly__)
+#define sival_ptr sigval_ptr
+#endif
+
#endif
diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h
index a9e26c2..f8a453d 100644
--- a/src/os/win32/ngx_socket.h
+++ b/src/os/win32/ngx_socket.h
@@ -200,6 +200,49 @@
extern LPFN_DISCONNECTEX ngx_disconnectex;
+#if (NGX_HAVE_POLL && !defined POLLIN)
+
+/*
+ * WSAPoll() is only available if _WIN32_WINNT >= 0x0600.
+ * If it is not available during compilation, we try to
+ * load it dynamically at runtime.
+ */
+
+#define NGX_LOAD_WSAPOLL 1
+
+#define POLLRDNORM 0x0100
+#define POLLRDBAND 0x0200
+#define POLLIN (POLLRDNORM | POLLRDBAND)
+#define POLLPRI 0x0400
+
+#define POLLWRNORM 0x0010
+#define POLLOUT (POLLWRNORM)
+#define POLLWRBAND 0x0020
+
+#define POLLERR 0x0001
+#define POLLHUP 0x0002
+#define POLLNVAL 0x0004
+
+typedef struct pollfd {
+
+ SOCKET fd;
+ SHORT events;
+ SHORT revents;
+
+} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD;
+
+typedef int (WSAAPI *ngx_wsapoll_pt)(
+ LPWSAPOLLFD fdArray,
+ ULONG fds,
+ INT timeout
+ );
+
+extern ngx_wsapoll_pt WSAPoll;
+extern ngx_uint_t ngx_have_wsapoll;
+
+#endif
+
+
int ngx_tcp_push(ngx_socket_t s);
#define ngx_tcp_push_n "tcp_push()"
diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c
index ec9b51e..70bee8e 100644
--- a/src/os/win32/ngx_win32_init.c
+++ b/src/os/win32/ngx_win32_init.c
@@ -58,6 +58,12 @@
static GUID dx_guid = WSAID_DISCONNECTEX;
+#if (NGX_LOAD_WSAPOLL)
+ngx_wsapoll_pt WSAPoll;
+ngx_uint_t ngx_have_wsapoll;
+#endif
+
+
ngx_int_t
ngx_os_init(ngx_log_t *log)
{
@@ -223,6 +229,32 @@
ngx_close_socket_n " failed");
}
+#if (NGX_LOAD_WSAPOLL)
+ {
+ HMODULE hmod;
+
+ hmod = GetModuleHandle("ws2_32.dll");
+ if (hmod == NULL) {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno,
+ "GetModuleHandle(\"ws2_32.dll\") failed");
+ goto nopoll;
+ }
+
+ WSAPoll = (ngx_wsapoll_pt) GetProcAddress(hmod, "WSAPoll");
+ if (WSAPoll == NULL) {
+ ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno,
+ "GetProcAddress(\"WSAPoll\") failed");
+ goto nopoll;
+ }
+
+ ngx_have_wsapoll = 1;
+
+ }
+
+nopoll:
+
+#endif
+
if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1)
!= 0)
{
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 0949313..d7bdec2 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -1593,7 +1593,7 @@
break;
}
- if ((off_t) size > limit) {
+ if (c->type == SOCK_STREAM && (off_t) size > limit) {
size = (size_t) limit;
}
}
@@ -1667,13 +1667,13 @@
flags = src->read->eof ? NGX_CLOSE_EVENT : 0;
- if (!src->shared && ngx_handle_read_event(src->read, flags) != NGX_OK) {
+ if (ngx_handle_read_event(src->read, flags) != NGX_OK) {
ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
return;
}
if (dst) {
- if (!dst->shared && ngx_handle_write_event(dst->write, 0) != NGX_OK) {
+ if (ngx_handle_write_event(dst->write, 0) != NGX_OK) {
ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
return;
}
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index dcc33e1..9266e99 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -22,6 +22,9 @@
static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl,
ngx_connection_t *c);
static void ngx_stream_ssl_handshake_handler(ngx_connection_t *c);
+#ifdef SSL_R_CERT_CB_ERROR
+static int ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg);
+#endif
static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s,
@@ -32,6 +35,9 @@
static char *ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent,
void *child);
+static ngx_int_t ngx_stream_ssl_compile_certificates(ngx_conf_t *cf,
+ ngx_stream_ssl_conf_t *conf);
+
static char *ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_stream_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -408,6 +414,62 @@
}
+#ifdef SSL_R_CERT_CB_ERROR
+
+int
+ngx_stream_ssl_certificate(ngx_ssl_conn_t *ssl_conn, void *arg)
+{
+ ngx_str_t cert, key;
+ ngx_uint_t i, nelts;
+ ngx_connection_t *c;
+ ngx_stream_session_t *s;
+ ngx_stream_ssl_conf_t *sslcf;
+ ngx_stream_complex_value_t *certs, *keys;
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ if (c->ssl->handshaked) {
+ return 0;
+ }
+
+ s = c->data;
+
+ sslcf = arg;
+
+ nelts = sslcf->certificate_values->nelts;
+ certs = sslcf->certificate_values->elts;
+ keys = sslcf->certificate_key_values->elts;
+
+ for (i = 0; i < nelts; i++) {
+
+ if (ngx_stream_complex_value(s, &certs[i], &cert) != NGX_OK) {
+ return 0;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "ssl cert: \"%s\"", cert.data);
+
+ if (ngx_stream_complex_value(s, &keys[i], &key) != NGX_OK) {
+ return 0;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
+ "ssl key: \"%s\"", key.data);
+
+ if (ngx_ssl_connection_certificate(c, c->pool, &cert, &key,
+ sslcf->passwords)
+ != NGX_OK)
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#endif
+
+
static ngx_int_t
ngx_stream_ssl_static_variable(ngx_stream_session_t *s,
ngx_stream_variable_value_t *v, uintptr_t data)
@@ -505,6 +567,7 @@
*
* scf->listen = 0;
* scf->protocols = 0;
+ * scf->certificate_values = NULL;
* scf->dhparam = { 0, NULL };
* scf->ecdh_curve = { 0, NULL };
* scf->client_certificate = { 0, NULL };
@@ -619,13 +682,38 @@
cln->handler = ngx_ssl_cleanup_ctx;
cln->data = &conf->ssl;
- if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
- conf->certificate_keys, conf->passwords)
- != NGX_OK)
- {
+ if (ngx_stream_ssl_compile_certificates(cf, conf) != NGX_OK) {
return NGX_CONF_ERROR;
}
+ if (conf->certificate_values) {
+
+#ifdef SSL_R_CERT_CB_ERROR
+
+ /* install callback to lookup certificates */
+
+ SSL_CTX_set_cert_cb(conf->ssl.ctx, ngx_stream_ssl_certificate, conf);
+
+#else
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "variables in "
+ "\"ssl_certificate\" and \"ssl_certificate_key\" "
+ "directives are not supported on this platform");
+ return NGX_CONF_ERROR;
+#endif
+
+ } else {
+
+ /* configure certificates */
+
+ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates,
+ conf->certificate_keys, conf->passwords)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers,
conf->prefer_server_ciphers)
!= NGX_OK)
@@ -678,7 +766,7 @@
}
if (ngx_ssl_session_cache(&conf->ssl, &ngx_stream_ssl_sess_id_ctx,
- conf->builtin_session_cache,
+ conf->certificates, conf->builtin_session_cache,
conf->shm_zone, conf->session_timeout)
!= NGX_OK)
{
@@ -707,6 +795,90 @@
}
+static ngx_int_t
+ngx_stream_ssl_compile_certificates(ngx_conf_t *cf,
+ ngx_stream_ssl_conf_t *conf)
+{
+ ngx_str_t *cert, *key;
+ ngx_uint_t i, nelts;
+ ngx_stream_complex_value_t *cv;
+ ngx_stream_compile_complex_value_t ccv;
+
+ cert = conf->certificates->elts;
+ key = conf->certificate_keys->elts;
+ nelts = conf->certificates->nelts;
+
+ for (i = 0; i < nelts; i++) {
+
+ if (ngx_stream_script_variables_count(&cert[i])) {
+ goto found;
+ }
+
+ if (ngx_stream_script_variables_count(&key[i])) {
+ goto found;
+ }
+ }
+
+ return NGX_OK;
+
+found:
+
+ conf->certificate_values = ngx_array_create(cf->pool, nelts,
+ sizeof(ngx_stream_complex_value_t));
+ if (conf->certificate_values == NULL) {
+ return NGX_ERROR;
+ }
+
+ conf->certificate_key_values = ngx_array_create(cf->pool, nelts,
+ sizeof(ngx_stream_complex_value_t));
+ if (conf->certificate_key_values == NULL) {
+ return NGX_ERROR;
+ }
+
+ for (i = 0; i < nelts; i++) {
+
+ cv = ngx_array_push(conf->certificate_values);
+ if (cv == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &cert[i];
+ ccv.complex_value = cv;
+ ccv.zero = 1;
+
+ if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ cv = ngx_array_push(conf->certificate_key_values);
+ if (cv == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &key[i];
+ ccv.complex_value = cv;
+ ccv.zero = 1;
+
+ if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ conf->passwords = ngx_ssl_preserve_passwords(cf, conf->passwords);
+ if (conf->passwords == NULL) {
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
static char *
ngx_stream_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h
index 9f8f01c..6cb4140 100644
--- a/src/stream/ngx_stream_ssl_module.h
+++ b/src/stream/ngx_stream_ssl_module.h
@@ -34,6 +34,9 @@
ngx_array_t *certificates;
ngx_array_t *certificate_keys;
+ ngx_array_t *certificate_values;
+ ngx_array_t *certificate_key_values;
+
ngx_str_t dhparam;
ngx_str_t ecdh_curve;
ngx_str_t client_certificate;