summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornginx <nginx@nginx.org>2014-05-27 14:08:36 +0000
committerJon Kolb <kolbyjack@gmail.com>2014-05-27 14:08:36 +0000
commitb72398c9a386f5100c857869af10a910d97549fe (patch)
treefb57fd6f2ab1b365af5f13f82058b43614c80414
parent7a8cd938c2c573a382568055e17e2a397c508b68 (diff)
downloadnginx-b72398c9a386f5100c857869af10a910d97549fe.tar.gz
Changes with nginx 1.7.1 27 May 2014v1.7.1
*) Feature: the "$upstream_cookie_..." variables. *) Feature: the $ssl_client_fingerprint variable. *) Feature: the "error_log" and "access_log" directives now support logging to syslog. *) Feature: the mail proxy now logs client port on connect. *) Bugfix: memory leak if the "ssl_stapling" directive was used. Thanks to Filipe da Silva. *) Bugfix: the "alias" directive used inside a location given by a regular expression worked incorrectly if the "if" or "limit_except" directives were used. *) Bugfix: the "charset" directive did not set a charset to encoded backend responses. *) Bugfix: a "proxy_pass" directive without URI part might use original request after the $args variable was set. Thanks to Yichun Zhang. *) Bugfix: in the "none" parameter in the "smtp_auth" directive; the bug had appeared in 1.5.6. Thanks to Svyatoslav Nikolsky. *) Bugfix: if sub_filter and SSI were used together, then responses might be transferred incorrectly. *) Bugfix: nginx could not be built with the --with-file-aio option on Linux/aarch64.
-rw-r--r--CHANGES36
-rw-r--r--CHANGES.ru38
-rw-r--r--auto/lib/google-perftools/conf2
-rw-r--r--auto/options3
-rw-r--r--auto/sources6
-rwxr-xr-xauto/unix33
-rwxr-xr-xconfigure4
-rw-r--r--src/core/nginx.c2
-rw-r--r--src/core/nginx.h10
-rw-r--r--src/core/ngx_conf_file.c2
-rw-r--r--src/core/ngx_core.h7
-rw-r--r--src/core/ngx_cycle.c6
-rw-r--r--src/core/ngx_log.c86
-rw-r--r--src/core/ngx_log.h6
-rw-r--r--src/core/ngx_syslog.c346
-rw-r--r--src/core/ngx_syslog.h30
-rw-r--r--src/core/ngx_times.c21
-rw-r--r--src/core/ngx_times.h1
-rw-r--r--src/event/modules/ngx_epoll_module.c8
-rw-r--r--src/event/ngx_event_accept.c14
-rw-r--r--src/event/ngx_event_openssl.c34
-rw-r--r--src/event/ngx_event_openssl.h2
-rw-r--r--src/event/ngx_event_openssl_stapling.c2
-rw-r--r--src/http/modules/ngx_http_charset_filter_module.c34
-rw-r--r--src/http/modules/ngx_http_gzip_static_module.c2
-rw-r--r--src/http/modules/ngx_http_log_module.c71
-rw-r--r--src/http/modules/ngx_http_proxy_module.c8
-rw-r--r--src/http/modules/ngx_http_ssl_module.c3
-rw-r--r--src/http/modules/ngx_http_sub_filter_module.c8
-rw-r--r--src/http/modules/ngx_http_upstream_ip_hash_module.c2
-rw-r--r--src/http/ngx_http.h2
-rw-r--r--src/http/ngx_http_core_module.c28
-rw-r--r--src/http/ngx_http_file_cache.c5
-rw-r--r--src/http/ngx_http_parse.c51
-rw-r--r--src/http/ngx_http_request.h3
-rw-r--r--src/http/ngx_http_spdy.c441
-rw-r--r--src/http/ngx_http_spdy_filter_module.c3
-rw-r--r--src/http/ngx_http_upstream.c65
-rw-r--r--src/http/ngx_http_upstream.h3
-rw-r--r--src/http/ngx_http_variables.c39
-rw-r--r--src/mail/ngx_mail_auth_http_module.c2
-rw-r--r--src/mail/ngx_mail_handler.c8
-rw-r--r--src/mail/ngx_mail_smtp_handler.c10
-rw-r--r--src/os/unix/ngx_linux_config.h3
-rw-r--r--src/os/unix/ngx_posix_init.c2
-rw-r--r--src/os/unix/ngx_process_cycle.c11
46 files changed, 1251 insertions, 252 deletions
diff --git a/CHANGES b/CHANGES
index d6d2d109b..6ad9e8a37 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,40 @@
+Changes with nginx 1.7.1 27 May 2014
+
+ *) Feature: the "$upstream_cookie_..." variables.
+
+ *) Feature: the $ssl_client_fingerprint variable.
+
+ *) Feature: the "error_log" and "access_log" directives now support
+ logging to syslog.
+
+ *) Feature: the mail proxy now logs client port on connect.
+
+ *) Bugfix: memory leak if the "ssl_stapling" directive was used.
+ Thanks to Filipe da Silva.
+
+ *) Bugfix: the "alias" directive used inside a location given by a
+ regular expression worked incorrectly if the "if" or "limit_except"
+ directives were used.
+
+ *) Bugfix: the "charset" directive did not set a charset to encoded
+ backend responses.
+
+ *) Bugfix: a "proxy_pass" directive without URI part might use original
+ request after the $args variable was set.
+ Thanks to Yichun Zhang.
+
+ *) Bugfix: in the "none" parameter in the "smtp_auth" directive; the bug
+ had appeared in 1.5.6.
+ Thanks to Svyatoslav Nikolsky.
+
+ *) Bugfix: if sub_filter and SSI were used together, then responses
+ might be transferred incorrectly.
+
+ *) Bugfix: nginx could not be built with the --with-file-aio option on
+ Linux/aarch64.
+
+
Changes with nginx 1.7.0 24 Apr 2014
*) Feature: backend SSL certificate verification.
diff --git a/CHANGES.ru b/CHANGES.ru
index bf1c99e48..876699d12 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,42 @@
+Изменения в nginx 1.7.1 27.05.2014
+
+ *) Добавление: переменные "$upstream_cookie_...".
+
+ *) Добавление: переменная $ssl_client_fingerprint.
+
+ *) Добавление: директивы error_log и access_log теперь поддерживают
+ логгирование в syslog.
+
+ *) Добавление: почтовый прокси-сервер теперь логгирует порт клиента при
+ соединении.
+
+ *) Исправление: утечки памяти при использовании директивы
+ "ssl_stapling".
+ Спасибо Filipe da Silva.
+
+ *) Исправление: директива alias внутри location'а, заданного регулярным
+ выражением, работала неправильно, если использовались директивы if
+ или limit_except.
+
+ *) Исправление: директива charset не ставила кодировку для сжатых
+ ответов бэкендов.
+
+ *) Исправление: директива proxy_pass без URI могла использовать
+ оригинальный запрос после установки переменной $args.
+ Спасибо Yichun Zhang.
+
+ *) Исправление: в работе параметра none директивы smtp_auth; ошибка
+ появилась в 1.5.6.
+ Спасибо Святославу Никольскому.
+
+ *) Исправление: при совместном использовании sub_filter и SSI ответы
+ могли передаваться неверно.
+
+ *) Исправление: nginx не собирался с параметром --with-file-aio на
+ Linux/aarch64.
+
+
Изменения в nginx 1.7.0 24.04.2014
*) Добавление: проверка SSL-сертификатов бэкендов.
diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf
index 7a9de3002..5d5ddaef6 100644
--- a/auto/lib/google-perftools/conf
+++ b/auto/lib/google-perftools/conf
@@ -52,7 +52,7 @@ else
cat << END
-$0: error: the Google perftool module requires the Google perftools
+$0: error: the Google perftools module requires the Google perftools
library. You can either do not enable the module or install the library.
END
diff --git a/auto/options b/auto/options
index 6cea8c7c2..010a6bbe2 100644
--- a/auto/options
+++ b/auto/options
@@ -14,6 +14,7 @@ NGX_PID_PATH=
NGX_LOCK_PATH=
NGX_USER=
NGX_GROUP=
+NGX_BUILD=
CC=${CC:-cc}
CPP=
@@ -178,6 +179,7 @@ do
--crossbuild=*) NGX_PLATFORM="$value" ;;
+ --build=*) NGX_BUILD="$value" ;;
--builddir=*) NGX_OBJS="$value" ;;
--with-rtsig_module) EVENT_RTSIG=YES ;;
@@ -341,6 +343,7 @@ cat << END
--group=GROUP set non-privileged group for
worker processes
+ --build=NAME set build name
--builddir=DIR set build directory
--with-rtsig_module enable rtsig module
diff --git a/auto/sources b/auto/sources
index bff0eb166..13c1531f7 100644
--- a/auto/sources
+++ b/auto/sources
@@ -37,7 +37,8 @@ CORE_DEPS="src/core/nginx.h \
src/core/ngx_resolver.h \
src/core/ngx_open_file_cache.h \
src/core/ngx_crypt.h \
- src/core/ngx_proxy_protocol.h"
+ src/core/ngx_proxy_protocol.h \
+ src/core/ngx_syslog.h"
CORE_SRCS="src/core/nginx.c \
@@ -69,7 +70,8 @@ CORE_SRCS="src/core/nginx.c \
src/core/ngx_resolver.c \
src/core/ngx_open_file_cache.c \
src/core/ngx_crypt.c \
- src/core/ngx_proxy_protocol.c"
+ src/core/ngx_proxy_protocol.c \
+ src/core/ngx_syslog.c"
REGEX_MODULE=ngx_regex_module
diff --git a/auto/unix b/auto/unix
index 10fd3d293..9b4764c6d 100755
--- a/auto/unix
+++ b/auto/unix
@@ -398,16 +398,36 @@ if [ $NGX_FILE_AIO = YES ]; then
if [ $ngx_found = yes ]; then
CORE_SRCS="$CORE_SRCS $FILE_AIO_SRCS"
+ fi
- elif [ $ngx_found = no ]; then
+ if [ $ngx_found = no ]; then
ngx_feature="Linux AIO support"
ngx_feature_name="NGX_HAVE_FILE_AIO"
ngx_feature_run=no
ngx_feature_incs="#include <linux/aio_abi.h>
- #include <sys/syscall.h>"
+ #include <sys/eventfd.h>"
ngx_feature_path=
ngx_feature_libs=
+ ngx_feature_test="struct iocb iocb;
+ iocb.aio_lio_opcode = IOCB_CMD_PREAD;
+ iocb.aio_flags = IOCB_FLAG_RESFD;
+ iocb.aio_resfd = -1;
+ (void) eventfd(0, 0)"
+ . auto/feature
+
+ if [ $ngx_found = yes ]; then
+ have=NGX_HAVE_EVENTFD . auto/have
+ have=NGX_HAVE_SYS_EVENTFD_H . auto/have
+ CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS"
+ fi
+ fi
+
+ if [ $ngx_found = no ]; then
+
+ ngx_feature="Linux AIO support (SYS_eventfd)"
+ ngx_feature_incs="#include <linux/aio_abi.h>
+ #include <sys/syscall.h>"
ngx_feature_test="int n = SYS_eventfd;
struct iocb iocb;
iocb.aio_lio_opcode = IOCB_CMD_PREAD;
@@ -418,16 +438,17 @@ if [ $NGX_FILE_AIO = YES ]; then
if [ $ngx_found = yes ]; then
have=NGX_HAVE_EVENTFD . auto/have
CORE_SRCS="$CORE_SRCS $LINUX_AIO_SRCS"
+ fi
+ fi
- else
- cat << END
+ if [ $ngx_found = no ]; then
+ cat << END
$0: no supported file AIO was found
Currently file AIO is supported on FreeBSD 4.3+ and Linux 2.6.22+ only
END
- exit 1
- fi
+ exit 1
fi
fi
diff --git a/configure b/configure
index d7d8189af..e8929b8f0 100755
--- a/configure
+++ b/configure
@@ -108,4 +108,8 @@ have=NGX_HTTP_SCGI_TEMP_PATH value="\"$NGX_HTTP_SCGI_TEMP_PATH\""
have=NGX_USER value="\"$NGX_USER\"" . auto/define
have=NGX_GROUP value="\"$NGX_GROUP\"" . auto/define
+if [ ".$NGX_BUILD" != "." ]; then
+ have=NGX_BUILD value="\"$NGX_BUILD\"" . auto/define
+fi
+
. auto/summary
diff --git a/src/core/nginx.c b/src/core/nginx.c
index 4cc80826e..c75ee4fd7 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -217,7 +217,7 @@ main(int argc, char *const *argv)
}
if (ngx_show_version) {
- ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED);
+ ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED);
if (ngx_show_help) {
ngx_write_stderr(
diff --git a/src/core/nginx.h b/src/core/nginx.h
index bd375c3cd..12e6e8a86 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,10 +9,16 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1007000
-#define NGINX_VERSION "1.7.0"
+#define nginx_version 1007001
+#define NGINX_VERSION "1.7.1"
#define NGINX_VER "nginx/" NGINX_VERSION
+#ifdef NGX_BUILD
+#define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")"
+#else
+#define NGINX_VER_BUILD NGINX_VER
+#endif
+
#define NGINX_VAR "NGINX"
#define NGX_OLDPID_EXT ".oldbin"
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index f61bfcabf..d6b5cdf1e 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -266,7 +266,7 @@ done:
ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
ngx_close_file_n " %s failed",
filename->data);
- return NGX_CONF_ERROR;
+ rc = NGX_ERROR;
}
cf->conf_file = prev;
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index a2d417e8d..aeea0c68b 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -77,12 +77,13 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
#include <ngx_open_file_cache.h>
#include <ngx_os.h>
#include <ngx_connection.h>
+#include <ngx_syslog.h>
#include <ngx_proxy_protocol.h>
-#define LF (u_char) 10
-#define CR (u_char) 13
-#define CRLF "\x0d\x0a"
+#define LF (u_char) '\n'
+#define CR (u_char) '\r'
+#define CRLF "\r\n"
#define ngx_abs(value) (((value) >= 0) ? (value) : - (value))
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index d1a89ae1a..d69783fec 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -1104,6 +1104,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
ngx_close_file_n " \"%s\" failed",
file[i].name.data);
}
+
+ continue;
}
if (fi.st_uid != user) {
@@ -1117,6 +1119,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
ngx_close_file_n " \"%s\" failed",
file[i].name.data);
}
+
+ continue;
}
}
@@ -1133,6 +1137,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
ngx_close_file_n " \"%s\" failed",
file[i].name.data);
}
+
+ continue;
}
}
}
diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c
index edf30043d..375d52f65 100644
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -148,6 +148,12 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
break;
}
+ if (log->writer) {
+ log->writer(log, level, errstr, p - errstr);
+ log = log->next;
+ continue;
+ }
+
(void) ngx_write_fd(log->file->fd, errstr, p - errstr);
if (log->file->fd == ngx_stderr) {
@@ -366,15 +372,33 @@ ngx_log_init(u_char *prefix)
ngx_int_t
ngx_log_open_default(ngx_cycle_t *cycle)
{
- static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH);
+ ngx_log_t *log;
+ static ngx_str_t error_log = ngx_string(NGX_ERROR_LOG_PATH);
+
+ if (ngx_log_get_file_log(&cycle->new_log) != NULL) {
+ return NGX_OK;
+ }
- if (cycle->new_log.file == NULL) {
- cycle->new_log.file = ngx_conf_open_file(cycle, &error_log);
- if (cycle->new_log.file == NULL) {
+ if (cycle->new_log.log_level != 0) {
+ /* there are some error logs, but no files */
+
+ log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t));
+ if (log == NULL) {
return NGX_ERROR;
}
- cycle->new_log.log_level = NGX_LOG_ERR;
+ log->log_level = NGX_LOG_ERR;
+ ngx_log_insert(&cycle->new_log, log);
+
+ } else {
+ /* no error logs at all */
+ log = &cycle->new_log;
+ log->log_level = NGX_LOG_ERR;
+ }
+
+ log->file = ngx_conf_open_file(cycle, &error_log);
+ if (log->file == NULL) {
+ return NGX_ERROR;
}
return NGX_OK;
@@ -390,7 +414,8 @@ ngx_log_redirect_stderr(ngx_cycle_t *cycle)
return NGX_OK;
}
- fd = cycle->log->file->fd;
+ /* file log always exists when we are called */
+ fd = ngx_log_get_file_log(cycle->log)->file->fd;
if (fd != ngx_stderr) {
if (ngx_set_stderr(fd) == NGX_FILE_ERROR) {
@@ -405,6 +430,21 @@ ngx_log_redirect_stderr(ngx_cycle_t *cycle)
}
+ngx_log_t *
+ngx_log_get_file_log(ngx_log_t *head)
+{
+ ngx_log_t *log;
+
+ for (log = head; log; log = log->next) {
+ if (log->file != NULL) {
+ return log;
+ }
+ }
+
+ return NULL;
+}
+
+
static char *
ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log)
{
@@ -482,8 +522,9 @@ ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
char *
ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
{
- ngx_log_t *new_log;
- ngx_str_t *value, name;
+ ngx_log_t *new_log;
+ ngx_str_t *value, name;
+ ngx_syslog_peer_t *peer;
if (*head != NULL && (*head)->log_level == 0) {
new_log = *head;
@@ -506,13 +547,30 @@ ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head)
ngx_str_null(&name);
cf->cycle->log_use_stderr = 1;
- } else {
- name = value[1];
- }
+ new_log->file = ngx_conf_open_file(cf->cycle, &name);
+ if (new_log->file == NULL) {
+ return NGX_CONF_ERROR;
+ }
- new_log->file = ngx_conf_open_file(cf->cycle, &name);
- if (new_log->file == NULL) {
- return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
+ if (peer == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ new_log->writer = ngx_syslog_writer;
+ new_log->wdata = peer;
+
+ } else {
+ new_log->file = ngx_conf_open_file(cf->cycle, &value[1]);
+ if (new_log->file == NULL) {
+ return NGX_CONF_ERROR;
+ }
}
if (ngx_log_set_levels(cf, new_log) != NGX_CONF_OK) {
diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h
index 878fb0a27..c1a52c44f 100644
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -43,6 +43,8 @@
typedef u_char *(*ngx_log_handler_pt) (ngx_log_t *log, u_char *buf, size_t len);
+typedef void (*ngx_log_writer_pt) (ngx_log_t *log, ngx_uint_t level,
+ u_char *buf, size_t len);
struct ngx_log_s {
@@ -54,6 +56,9 @@ struct ngx_log_s {
ngx_log_handler_pt handler;
void *data;
+ ngx_log_writer_pt writer;
+ void *wdata;
+
/*
* we declare "action" as "char *" because the actions are usually
* the static strings and in the "u_char *" case we have to override
@@ -227,6 +232,7 @@ void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...);
u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err);
ngx_int_t ngx_log_open_default(ngx_cycle_t *cycle);
ngx_int_t ngx_log_redirect_stderr(ngx_cycle_t *cycle);
+ngx_log_t *ngx_log_get_file_log(ngx_log_t *head);
char *ngx_log_set_log(ngx_conf_t *cf, ngx_log_t **head);
diff --git a/src/core/ngx_syslog.c b/src/core/ngx_syslog.c
new file mode 100644
index 000000000..e6d40f48a
--- /dev/null
+++ b/src/core/ngx_syslog.c
@@ -0,0 +1,346 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+#define NGX_SYSLOG_MAX_STR \
+ NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \
+ + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \
+ + 32 /* tag */ + 2 /* colon, space */
+
+
+static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
+static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
+static void ngx_syslog_cleanup(void *data);
+
+
+static char *facilities[] = {
+ "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
+ "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
+ "local1", "local2", "local3", "local4", "local5", "local6", "local7",
+ NULL
+};
+
+/* note 'error/warn' like in nginx.conf, not 'err/warning' */
+static char *severities[] = {
+ "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
+};
+
+static ngx_log_t ngx_syslog_dummy_log;
+static ngx_event_t ngx_syslog_dummy_event;
+
+
+char *
+ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
+{
+ peer->pool = cf->pool;
+ peer->facility = NGX_CONF_UNSET_UINT;
+ peer->severity = NGX_CONF_UNSET_UINT;
+
+ if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (peer->server.sockaddr == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "no syslog server specified");
+ return NGX_CONF_ERROR;
+ }
+
+ if (peer->facility == NGX_CONF_UNSET_UINT) {
+ peer->facility = 23; /* local7 */
+ }
+
+ if (peer->severity == NGX_CONF_UNSET_UINT) {
+ peer->severity = 6; /* info */
+ }
+
+ if (peer->tag.data == NULL) {
+ ngx_str_set(&peer->tag, "nginx");
+ }
+
+ peer->conn.fd = (ngx_socket_t) -1;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
+{
+ u_char *p, *comma, c;
+ size_t len;
+ ngx_str_t *value;
+ ngx_url_t u;
+ ngx_uint_t i;
+
+ value = cf->args->elts;
+
+ p = value[1].data + sizeof("syslog:") - 1;
+
+ for ( ;; ) {
+ comma = (u_char *) ngx_strchr(p, ',');
+
+ if (comma != NULL) {
+ len = comma - p;
+ *comma = '\0';
+
+ } else {
+ len = value[1].data + value[1].len - p;
+ }
+
+ if (ngx_strncmp(p, "server=", 7) == 0) {
+
+ if (peer->server.sockaddr != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"server\"");
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(&u, sizeof(ngx_url_t));
+
+ u.url.data = p + 7;
+ u.url.len = len - 7;
+ u.default_port = 514;
+
+ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+ if (u.err) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "%s in syslog server \"%V\"",
+ u.err, &u.url);
+ }
+
+ return NGX_CONF_ERROR;
+ }
+
+ peer->server = u.addrs[0];
+
+ } else if (ngx_strncmp(p, "facility=", 9) == 0) {
+
+ if (peer->facility != NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"facility\"");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; facilities[i] != NULL; i++) {
+
+ if (ngx_strcmp(p + 9, facilities[i]) == 0) {
+ peer->facility = i;
+ goto next;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog facility \"%s\"", p + 9);
+ return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(p, "severity=", 9) == 0) {
+
+ if (peer->severity != NGX_CONF_UNSET_UINT) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"severity\"");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 0; severities[i] != NULL; i++) {
+
+ if (ngx_strcmp(p + 9, severities[i]) == 0) {
+ peer->severity = i;
+ goto next;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog severity \"%s\"", p + 9);
+ return NGX_CONF_ERROR;
+
+ } else if (ngx_strncmp(p, "tag=", 4) == 0) {
+
+ if (peer->tag.data != NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate syslog \"tag\"");
+ return NGX_CONF_ERROR;
+ }
+
+ /*
+ * RFC 3164: the TAG is a string of ABNF alphanumeric characters
+ * that MUST NOT exceed 32 characters.
+ */
+ if (len - 4 > 32) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "syslog tag length exceeds 32");
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 4; i < len; i++) {
+ c = ngx_tolower(p[i]);
+
+ if (c < '0' || (c > '9' && c < 'a') || c > 'z') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "syslog \"tag\" only allows "
+ "alphanumeric characters");
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ peer->tag.data = p + 4;
+ peer->tag.len = len - 4;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "unknown syslog parameter \"%s\"", p);
+ return NGX_CONF_ERROR;
+ }
+
+ next:
+
+ if (comma == NULL) {
+ break;
+ }
+
+ p = comma + 1;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+u_char *
+ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
+{
+ ngx_uint_t pri;
+
+ pri = peer->facility * 8 + peer->severity;
+
+ return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
+ &ngx_cycle->hostname, &peer->tag);
+}
+
+
+void
+ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len)
+{
+ u_char *p, msg[NGX_SYSLOG_MAX_STR];
+ ngx_uint_t head_len;
+ ngx_syslog_peer_t *peer;
+
+ peer = log->wdata;
+
+ if (peer->processing) {
+ return;
+ }
+
+ peer->processing = 1;
+ peer->severity = level - 1;
+
+ p = ngx_syslog_add_header(peer, msg);
+ head_len = p - msg;
+
+ len -= NGX_LINEFEED_SIZE;
+
+ if (len > NGX_SYSLOG_MAX_STR - head_len) {
+ len = NGX_SYSLOG_MAX_STR - head_len;
+ }
+
+ p = ngx_snprintf(p, len, "%s", buf);
+
+ (void) ngx_syslog_send(peer, msg, p - msg);
+
+ peer->processing = 0;
+}
+
+
+ssize_t
+ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
+{
+ if (peer->conn.fd == (ngx_socket_t) -1) {
+ if (ngx_syslog_init_peer(peer) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+
+ if (ngx_send) {
+ return ngx_send(&peer->conn, buf, len);
+
+ } else {
+ /* event module has not yet set ngx_io */
+ return ngx_os_io.send(&peer->conn, buf, len);
+ }
+}
+
+
+static ngx_int_t
+ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
+{
+ ngx_socket_t fd;
+ ngx_pool_cleanup_t *cln;
+
+ peer->conn.read = &ngx_syslog_dummy_event;
+ peer->conn.write = &ngx_syslog_dummy_event;
+ peer->conn.log = &ngx_syslog_dummy_log;
+
+ ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
+
+ fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
+ if (fd == (ngx_socket_t) -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_socket_n " failed");
+ return NGX_ERROR;
+ }
+
+ if (ngx_nonblocking(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_nonblocking_n " failed");
+ goto failed;
+ }
+
+ if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ "connect() failed");
+ goto failed;
+ }
+
+ cln = ngx_pool_cleanup_add(peer->pool, 0);
+ if (cln == NULL) {
+ goto failed;
+ }
+
+ cln->data = peer;
+ cln->handler = ngx_syslog_cleanup;
+
+ peer->conn.fd = fd;
+
+ /* UDP sockets are always ready to write */
+ peer->conn.write->ready = 1;
+
+ return NGX_OK;
+
+failed:
+
+ if (ngx_close_socket(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+
+ return NGX_ERROR;
+}
+
+
+static void
+ngx_syslog_cleanup(void *data)
+{
+ ngx_syslog_peer_t *peer = data;
+
+ if (ngx_close_socket(peer->conn.fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+ ngx_close_socket_n " failed");
+ }
+}
diff --git a/src/core/ngx_syslog.h b/src/core/ngx_syslog.h
new file mode 100644
index 000000000..92d47d5f5
--- /dev/null
+++ b/src/core/ngx_syslog.h
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#ifndef _NGX_SYSLOG_H_INCLUDED_
+#define _NGX_SYSLOG_H_INCLUDED_
+
+
+typedef struct {
+ ngx_pool_t *pool;
+ ngx_uint_t facility;
+ ngx_uint_t severity;
+ ngx_str_t tag;
+
+ ngx_addr_t server;
+ ngx_connection_t conn;
+ ngx_uint_t processing; /* unsigned processing:1; */
+} ngx_syslog_peer_t;
+
+
+char *ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
+u_char *ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf);
+void ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
+ size_t len);
+ssize_t ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len);
+
+
+#endif /* _NGX_SYSLOG_H_INCLUDED_ */
diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c
index 77490faf0..595c1224d 100644
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -29,6 +29,7 @@ volatile ngx_str_t ngx_cached_err_log_time;
volatile ngx_str_t ngx_cached_http_time;
volatile ngx_str_t ngx_cached_http_log_time;
volatile ngx_str_t ngx_cached_http_log_iso8601;
+volatile ngx_str_t ngx_cached_syslog_time;
#if !(NGX_WIN32)
@@ -50,6 +51,8 @@ static u_char cached_http_log_time[NGX_TIME_SLOTS]
[sizeof("28/Sep/1970:12:00:00 +0600")];
static u_char cached_http_log_iso8601[NGX_TIME_SLOTS]
[sizeof("1970-09-28T12:00:00+06:00")];
+static u_char cached_syslog_time[NGX_TIME_SLOTS]
+ [sizeof("Sep 28 12:00:00")];
static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
@@ -63,6 +66,7 @@ ngx_time_init(void)
ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1;
ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1;
ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
+ ngx_cached_syslog_time.len = sizeof("Sep 28 12:00:00") - 1;
ngx_cached_time = &cached_time[0];
@@ -73,7 +77,7 @@ ngx_time_init(void)
void
ngx_time_update(void)
{
- u_char *p0, *p1, *p2, *p3;
+ u_char *p0, *p1, *p2, *p3, *p4;
ngx_tm_t tm, gmt;
time_t sec;
ngx_uint_t msec;
@@ -166,6 +170,11 @@ ngx_time_update(void)
tp->gmtoff < 0 ? '-' : '+',
ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60));
+ p4 = &cached_syslog_time[slot][0];
+
+ (void) ngx_sprintf(p4, "%s %2d %02d:%02d:%02d",
+ months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
ngx_memory_barrier();
@@ -174,6 +183,7 @@ ngx_time_update(void)
ngx_cached_err_log_time.data = p1;
ngx_cached_http_log_time.data = p2;
ngx_cached_http_log_iso8601.data = p3;
+ ngx_cached_syslog_time.data = p4;
ngx_unlock(&ngx_time_lock);
}
@@ -184,7 +194,7 @@ ngx_time_update(void)
void
ngx_time_sigsafe_update(void)
{
- u_char *p;
+ u_char *p, *p2;
ngx_tm_t tm;
time_t sec;
ngx_time_t *tp;
@@ -224,9 +234,16 @@ ngx_time_sigsafe_update(void)
tm.ngx_tm_mday, tm.ngx_tm_hour,
tm.ngx_tm_min, tm.ngx_tm_sec);
+ p2 = &cached_syslog_time[slot][0];
+
+ (void) ngx_sprintf(p2, "%s %2d %02d:%02d:%02d",
+ months[tm.ngx_tm_mon - 1], tm.ngx_tm_mday,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
+
ngx_memory_barrier();
ngx_cached_err_log_time.data = p;
+ ngx_cached_syslog_time.data = p2;
ngx_unlock(&ngx_time_lock);
}
diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h
index c4b26a2ed..94aedcdc9 100644
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -40,6 +40,7 @@ extern volatile ngx_str_t ngx_cached_err_log_time;
extern volatile ngx_str_t ngx_cached_http_time;
extern volatile ngx_str_t ngx_cached_http_log_time;
extern volatile ngx_str_t ngx_cached_http_log_iso8601;
+extern volatile ngx_str_t ngx_cached_syslog_time;
/*
* milliseconds elapsed since epoch and truncated to ngx_msec_t,
diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c
index f5f663179..a098c1c00 100644
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -193,10 +193,6 @@ ngx_module_t ngx_epoll_module = {
* We call io_setup(), io_destroy() io_submit(), and io_getevents() directly
* as syscalls instead of libaio usage, because the library header file
* supports eventfd() since 0.3.107 version only.
- *
- * Also we do not use eventfd() in glibc, because glibc supports it
- * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2()
- * into single eventfd() function with different number of parameters.
*/
static int
@@ -227,7 +223,11 @@ ngx_epoll_aio_init(ngx_cycle_t *cycle, ngx_epoll_conf_t *epcf)
int n;
struct epoll_event ee;
+#if (NGX_HAVE_SYS_EVENTFD_H)
+ ngx_eventfd = eventfd(0, 0);
+#else
ngx_eventfd = syscall(SYS_eventfd, 0);
+#endif
if (ngx_eventfd == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c
index bf67ecee0..575ee4bdb 100644
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -288,9 +288,11 @@ ngx_event_accept(ngx_event_t *ev)
#if (NGX_DEBUG)
{
+ ngx_str_t addr;
struct sockaddr_in *sin;
ngx_cidr_t *cidr;
ngx_uint_t i;
+ u_char text[NGX_SOCKADDR_STRLEN];
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
ngx_uint_t n;
@@ -340,11 +342,17 @@ ngx_event_accept(ngx_event_t *ev)
continue;
}
+ if (log->log_level & NGX_LOG_DEBUG_EVENT) {
+ addr.data = text;
+ addr.len = ngx_sock_ntop(c->sockaddr, c->socklen, text,
+ NGX_SOCKADDR_STRLEN, 1);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
+ "*%uA accept: %V fd:%d", c->number, &addr, s);
}
-#endif
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
- "*%uA accept: %V fd:%d", c->number, &c->addr_text, s);
+ }
+#endif
if (ngx_add_conn && (ngx_event_flags & NGX_USE_EPOLL_EVENT) == 0) {
if (ngx_add_conn(c) == NGX_ERROR) {
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 88472fc90..0c5ecda98 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2957,6 +2957,40 @@ ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
ngx_int_t
+ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
+{
+ X509 *cert;
+ unsigned int len;
+ u_char buf[EVP_MAX_MD_SIZE];
+
+ s->len = 0;
+
+ cert = SSL_get_peer_certificate(c->ssl->connection);
+ if (cert == NULL) {
+ return NGX_OK;
+ }
+
+ if (!X509_digest(cert, EVP_sha1(), buf, &len)) {
+ X509_free(cert);
+ return NGX_ERROR;
+ }
+
+ s->len = 2 * len;
+ s->data = ngx_pnalloc(pool, 2 * len);
+ if (s->data == NULL) {
+ X509_free(cert);
+ return NGX_ERROR;
+ }
+
+ ngx_hex_dump(s->data, buf, len);
+
+ X509_free(cert);
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
{
X509 *cert;
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 30c8a7409..d632eb274 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -173,6 +173,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
+ngx_int_t ngx_ssl_get_fingerprint(ngx_connection_t *c, ngx_pool_t *pool,
+ ngx_str_t *s);
ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c
index 3a3cc7f9e..69340b37b 100644
--- a/src/event/ngx_event_openssl_stapling.c
+++ b/src/event/ngx_event_openssl_stapling.c
@@ -1195,6 +1195,8 @@ ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx)
b->last = p;
ctx->request = b;
+ OCSP_REQUEST_free(ocsp);
+
return NGX_OK;
failed:
diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c
index c9b7e9e89..4ea98184b 100644
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -272,12 +272,27 @@ ngx_http_charset_header_filter(ngx_http_request_t *r)
return ngx_http_next_header_filter(r);
}
+ if (source_charset == charset) {
+ r->headers_out.content_type.len = r->headers_out.content_type_len;
+
+ ngx_http_set_charset(r, &dst);
+
+ return ngx_http_next_header_filter(r);
+ }
+
+ /* source_charset != charset */
+
+ if (r->headers_out.content_encoding
+ && r->headers_out.content_encoding->value.len)
+ {
+ return ngx_http_next_header_filter(r);
+ }
+
mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module);
charsets = mcf->charsets.elts;
- if (source_charset != charset
- && (charsets[source_charset].tables == NULL
- || charsets[source_charset].tables[charset] == NULL))
+ if (charsets[source_charset].tables == NULL
+ || charsets[source_charset].tables[charset] == NULL)
{
goto no_charset_map;
}
@@ -286,11 +301,7 @@ ngx_http_charset_header_filter(ngx_http_request_t *r)
ngx_http_set_charset(r, &dst);
- if (source_charset != charset) {
- return ngx_http_charset_ctx(r, charsets, charset, source_charset);
- }
-
- return ngx_http_next_header_filter(r);
+ return ngx_http_charset_ctx(r, charsets, charset, source_charset);
no_charset_map:
@@ -311,13 +322,6 @@ ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name)
ngx_http_charset_loc_conf_t *mlcf;
ngx_http_charset_main_conf_t *mcf;
- if (!r->ignore_content_encoding
- && r->headers_out.content_encoding
- && r->headers_out.content_encoding->value.len)
- {
- return NGX_DECLINED;
- }
-
if (r->headers_out.content_type.len == 0) {
return NGX_DECLINED;
}
diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c
index 1746e5504..4d5409077 100644
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -246,8 +246,6 @@ ngx_http_gzip_static_handler(ngx_http_request_t *r)
ngx_str_set(&h->value, "gzip");
r->headers_out.content_encoding = h;
- r->ignore_content_encoding = 1;
-
/* we need to allocate all before the header would be sent */
b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c
index 592028fa9..f51ba938d 100644
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -66,6 +66,7 @@ typedef struct {
ngx_http_log_script_t *script;
time_t disk_full_time;
time_t error_log_time;
+ ngx_syslog_peer_t *syslog_peer;
ngx_http_log_fmt_t *format;
ngx_http_complex_value_t *filter;
} ngx_http_log_t;
@@ -240,7 +241,8 @@ static ngx_int_t
ngx_http_log_handler(ngx_http_request_t *r)
{
u_char *line, *p;
- size_t len;
+ size_t len, size;
+ ssize_t n;
ngx_str_t val;
ngx_uint_t i, l;
ngx_http_log_t *log;
@@ -294,6 +296,16 @@ ngx_http_log_handler(ngx_http_request_t *r)
}
}
+ if (log[l].syslog_peer) {
+
+ /* length of syslog's PRI and HEADER message parts */
+ len += sizeof("<255>Jan 01 00:00:00 ") - 1
+ + ngx_cycle->hostname.len + 1
+ + log[l].syslog_peer->tag.len + 2;
+
+ goto alloc_line;
+ }
+
len += NGX_LINEFEED_SIZE;
buffer = log[l].file ? log[l].file->data : NULL;
@@ -332,6 +344,8 @@ ngx_http_log_handler(ngx_http_request_t *r)
}
}
+ alloc_line:
+
line = ngx_pnalloc(r->pool, len);
if (line == NULL) {
return NGX_ERROR;
@@ -339,10 +353,33 @@ ngx_http_log_handler(ngx_http_request_t *r)
p = line;
+ if (log[l].syslog_peer) {
+ p = ngx_syslog_add_header(log[l].syslog_peer, line);
+ }
+
for (i = 0; i < log[l].format->ops->nelts; i++) {
p = op[i].run(r, p, &op[i]);
}
+ if (log[l].syslog_peer) {
+
+ size = p - line;
+
+ n = ngx_syslog_send(log[l].syslog_peer, line, size);
+
+ if (n < 0) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "send() to syslog failed");
+
+ } else if ((size_t) n != size) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "send() to syslog has written only %z of %uz",
+ n, size);
+ }
+
+ continue;
+ }
+
ngx_linefeed(p);
ngx_http_log_write(r, &log[l], line, p - line);
@@ -1080,6 +1117,7 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
log->script = NULL;
log->disk_full_time = 0;
log->error_log_time = 0;
+ log->syslog_peer = NULL;
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
fmt = lmcf->formats.elts;
@@ -1103,6 +1141,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_msec_t flush;
ngx_str_t *value, name, s, filter;
ngx_http_log_t *log;
+ ngx_syslog_peer_t *peer;
ngx_http_log_buf_t *buffer;
ngx_http_log_fmt_t *fmt;
ngx_http_log_main_conf_t *lmcf;
@@ -1138,6 +1177,23 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_memzero(log, sizeof(ngx_http_log_t));
+
+ if (ngx_strncmp(value[1].data, "syslog:", 7) == 0) {
+
+ peer = ngx_pcalloc(cf->pool, sizeof(ngx_syslog_peer_t));
+ if (peer == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_syslog_process_conf(cf, peer) != NGX_CONF_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ log->syslog_peer = peer;
+
+ goto process_formats;
+ }
+
n = ngx_http_script_variables_count(&value[1]);
if (n == 0) {
@@ -1171,6 +1227,8 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
}
+process_formats:
+
if (cf->args->nelts >= 3) {
name = value[2];
@@ -1199,6 +1257,17 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
+ if (log->syslog_peer != NULL) {
+ if (cf->args->nelts > 3) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "parameter \"%V\" is not supported by syslog",
+ &value[3]);
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+ }
+
size = 0;
flush = 0;
gzip = 0;
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index cf7d677ae..61af3dfd3 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1294,7 +1294,7 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http proxy header:\n\"%*s\"",
+ "http proxy header:%N\"%*s\"",
(size_t) (b->last - b->pos), b->pos);
if (plcf->body_set == NULL && plcf->upstream.pass_request_body) {
@@ -2365,7 +2365,7 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
if (replacement->len > len) {
- data = ngx_pnalloc(r->pool, new_len);
+ data = ngx_pnalloc(r->pool, new_len + 1);
if (data == NULL) {
return NGX_ERROR;
}
@@ -2374,7 +2374,7 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
p = ngx_copy(p, replacement->data, replacement->len);
ngx_memcpy(p, h->value.data + prefix + len,
- h->value.len - len - prefix);
+ h->value.len - len - prefix + 1);
h->value.data = data;
@@ -2383,7 +2383,7 @@ ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
replacement->len);
ngx_memmove(p, h->value.data + prefix + len,
- h->value.len - len - prefix);
+ h->value.len - len - prefix + 1);
}
h->value.len = new_len;
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 60049e689..730204cbb 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -292,6 +292,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
{ ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 },
+ { ngx_string("ssl_client_fingerprint"), NULL, ngx_http_ssl_variable,
+ (uintptr_t) ngx_ssl_get_fingerprint, NGX_HTTP_VAR_CHANGEABLE, 0 },
+
{ ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable,
(uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 },
diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c
index a4d666bed..3ba59d627 100644
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -305,6 +305,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
b->last = ctx->copy_end;
b->shadow = NULL;
b->last_buf = 0;
+ b->last_in_chain = 0;
b->recycled = 0;
if (b->in_file) {
@@ -374,7 +375,9 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
continue;
}
- if (ctx->buf->last_buf && ctx->looked.len) {
+ if (ctx->looked.len
+ && (ctx->buf->last_buf || ctx->buf->last_in_chain))
+ {
cl = ngx_chain_get_free_buf(r->pool, &ctx->free);
if (cl == NULL) {
return NGX_ERROR;
@@ -394,7 +397,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
ctx->looked.len = 0;
}
- if (ctx->buf->last_buf || ctx->buf->flush
+ if (ctx->buf->last_buf || ctx->buf->flush || ctx->buf->sync
|| ngx_buf_in_memory(ctx->buf))
{
if (b == NULL) {
@@ -414,6 +417,7 @@ ngx_http_sub_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
b->last_buf = ctx->buf->last_buf;
+ b->last_in_chain = ctx->buf->last_in_chain;
b->flush = ctx->buf->flush;
b->shadow = ctx->buf;
diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
index 041883fec..148d73a84 100644
--- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -231,7 +231,7 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
next:
- if (++iphp->tries >= 20) {
+ if (++iphp->tries > 20) {
return iphp->get_rr_peer(pc, &iphp->rrp);
}
}
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index d4dc1bd94..0acc23494 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -105,6 +105,8 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
ngx_uint_t allow_underscores);
ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers,
ngx_str_t *name, ngx_str_t *value);
+ngx_int_t ngx_http_parse_set_cookie_lines(ngx_array_t *headers,
+ ngx_str_t *name, ngx_str_t *value);
ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len,
ngx_str_t *value);
void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 4484a5ed4..741a80d93 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1245,10 +1245,8 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
if (!alias) {
reserve = len > r->uri.len ? len - r->uri.len : 0;
-#if (NGX_PCRE)
- } else if (clcf->regex) {
+ } else if (alias == NGX_MAX_SIZE_T_VALUE) {
reserve = len;
-#endif
} else {
reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0;
@@ -1365,13 +1363,12 @@ ngx_http_core_try_files_phase(ngx_http_request_t *r,
if (!alias) {
r->uri = path;
-#if (NGX_PCRE)
- } else if (clcf->regex) {
+ } else if (alias == NGX_MAX_SIZE_T_VALUE) {
if (!test_dir) {
r->uri = path;
r->add_uri_to_alias = 1;
}
-#endif
+
} else {
r->uri.len = alias + path.len;
r->uri.data = ngx_pnalloc(r->pool, r->uri.len);
@@ -2006,16 +2003,12 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
} else {
-#if (NGX_PCRE)
- ngx_uint_t captures;
-
- captures = alias && clcf->regex;
+ if (alias == NGX_MAX_SIZE_T_VALUE) {
+ reserved += r->add_uri_to_alias ? r->uri.len + 1 : 1;
- reserved += captures ? r->add_uri_to_alias ? r->uri.len + 1 : 1
- : r->uri.len - alias + 1;
-#else
- reserved += r->uri.len - alias + 1;
-#endif
+ } else {
+ reserved += r->uri.len - alias + 1;
+ }
if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved,
clcf->root_values->elts)
@@ -2033,8 +2026,7 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
*root_length = path->len - reserved;
last = path->data + *root_length;
-#if (NGX_PCRE)
- if (captures) {
+ if (alias == NGX_MAX_SIZE_T_VALUE) {
if (!r->add_uri_to_alias) {
*last = '\0';
return last;
@@ -2042,7 +2034,6 @@ ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *path,
alias = 0;
}
-#endif
}
last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1);
@@ -4476,6 +4467,7 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_PCRE)
if (alias && clcf->regex) {
+ clcf->alias = NGX_MAX_SIZE_T_VALUE;
n = 1;
}
#endif
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 9e6be1584..49abdb400 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1313,6 +1313,11 @@ ngx_http_file_cache_expire(ngx_http_file_cache_t *cache)
for ( ;; ) {
+ if (ngx_quit || ngx_terminate) {
+ wait = 1;
+ break;
+ }
+
if (ngx_queue_empty(&cache->sh->queue)) {
wait = 10;
break;
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 02b4a0fd1..f28786946 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1985,6 +1985,57 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
ngx_int_t
+ngx_http_parse_set_cookie_lines(ngx_array_t *headers, ngx_str_t *name,
+ ngx_str_t *value)
+{
+ ngx_uint_t i;
+ u_char *start, *last, *end;
+ ngx_table_elt_t **h;
+
+ h = headers->elts;
+
+ for (i = 0; i < headers->nelts; i++) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, headers->pool->log, 0,
+ "parse header: \"%V: %V\"", &h[i]->key, &h[i]->value);
+
+ if (name->len >= h[i]->value.len) {
+ continue;
+ }
+
+ start = h[i]->value.data;
+ end = h[i]->value.data + h[i]->value.len;
+
+ if (ngx_strncasecmp(start, name->data, name->len) != 0) {
+ continue;
+ }
+
+ for (start += name->len; start < end && *start == ' '; start++) {
+ /* void */
+ }
+
+ if (start == end || *start++ != '=') {
+ /* the invalid header value */
+ continue;
+ }
+
+ while (start < end && *start == ' ') { start++; }
+
+ for (last = start; last < end && *last != ';'; last++) {
+ /* void */
+ }
+
+ value->len = last - start;
+ value->data = start;
+
+ return i;
+ }
+
+ return NGX_DECLINED;
+}
+
+
+ngx_int_t
ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value)
{
u_char *p, *last;
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 705c4e904..0d3a79915 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -511,7 +511,6 @@ struct ngx_http_request_s {
unsigned discard_body:1;
unsigned internal:1;
unsigned error_page:1;
- unsigned ignore_content_encoding:1;
unsigned filter_finalize:1;
unsigned post_action:1;
unsigned request_complete:1;
@@ -588,6 +587,8 @@ extern ngx_http_header_out_t ngx_http_headers_out[];
\
c->log->file = l->file; \
c->log->next = l->next; \
+ c->log->writer = l->writer; \
+ c->log->wdata = l->wdata; \
if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { \
c->log->log_level = l->log_level; \
}
diff --git a/src/http/ngx_http_spdy.c b/src/http/ngx_http_spdy.c
index a09e4ac0b..810d8d8f4 100644
--- a/src/http/ngx_http_spdy.c
+++ b/src/http/ngx_http_spdy.c
@@ -103,10 +103,10 @@ static u_char *ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
-static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
- u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
+static u_char *ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc,
+ u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc,
@@ -125,6 +125,9 @@ static u_char *ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end);
static u_char *ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
u_char *pos, u_char *end, ngx_http_spdy_handler_pt handler);
+
+static u_char *ngx_http_spdy_state_inflate_error(
+ ngx_http_spdy_connection_t *sc, int rc);
static u_char *ngx_http_spdy_state_protocol_error(
ngx_http_spdy_connection_t *sc);
static u_char *ngx_http_spdy_state_internal_error(
@@ -392,8 +395,7 @@ ngx_http_spdy_init(ngx_event_t *rev)
c = rev->data;
hc = c->data;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "init spdy request");
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "init spdy request");
c->log->action = "processing SPDY";
@@ -421,12 +423,8 @@ ngx_http_spdy_init(ngx_event_t *rev)
sc->init_window = NGX_SPDY_INIT_STREAM_WINDOW;
- sc->handler = ngx_http_spdy_state_head;
-
- if (hc->proxy_protocol) {
- c->log->action = "reading PROXY protocol";
- sc->handler = ngx_http_spdy_proxy_protocol;
- }
+ sc->handler = hc->proxy_protocol ? ngx_http_spdy_proxy_protocol
+ : ngx_http_spdy_state_head;
sc->zstream_in.zalloc = ngx_http_spdy_zalloc;
sc->zstream_in.zfree = ngx_http_spdy_zfree;
@@ -557,7 +555,7 @@ ngx_http_spdy_read_handler(ngx_event_t *rev)
if (n == 0 && (sc->incomplete || sc->processing)) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client closed prematurely connection");
+ "client prematurely closed connection");
}
if (n == 0 || n == NGX_ERROR) {
@@ -645,7 +643,7 @@ ngx_http_spdy_write_handler(ngx_event_t *wev)
stream->handled = 0;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "spdy run stream %ui", stream->id);
+ "run spdy stream %ui", stream->id);
wev = stream->request->connection->write;
wev->handler(wev);
@@ -820,14 +818,19 @@ static u_char *
ngx_http_spdy_proxy_protocol(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
+ ngx_log_t *log;
+
+ log = sc->connection->log;
+ log->action = "reading PROXY protocol";
+
pos = ngx_proxy_protocol_parse(sc->connection, pos, end);
+ log->action = "processing SPDY";
+
if (pos == NULL) {
return ngx_http_spdy_state_protocol_error(sc);
}
- sc->connection->log->action = "processing SPDY";
-
return ngx_http_spdy_state_complete(sc, pos, end);
}
@@ -856,7 +859,7 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
pos += sizeof(uint32_t);
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy process frame head:%08XD f:%Xd l:%uz",
+ "process spdy frame head:%08XD f:%Xd l:%uz",
head, sc->flags, sc->length);
if (ngx_spdy_ctl_frame_check(head)) {
@@ -868,6 +871,8 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
return ngx_http_spdy_state_syn_stream(sc, pos, end);
case NGX_SPDY_SYN_REPLY:
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent unexpected SYN_REPLY frame");
return ngx_http_spdy_state_protocol_error(sc);
case NGX_SPDY_RST_STREAM:
@@ -883,6 +888,8 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
return ngx_http_spdy_state_skip(sc, pos, end); /* TODO */
case NGX_SPDY_HEADERS:
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent unexpected HEADERS frame");
return ngx_http_spdy_state_protocol_error(sc);
case NGX_SPDY_WINDOW_UPDATE:
@@ -900,10 +907,8 @@ ngx_http_spdy_state_head(ngx_http_spdy_connection_t *sc, u_char *pos,
return ngx_http_spdy_state_data(sc, pos, end);
}
-
- /* TODO version & type check */
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy unknown frame");
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent invalid frame");
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -923,7 +928,10 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
}
if (sc->length <= NGX_SPDY_SYN_STREAM_SIZE) {
- /* TODO logging */
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent SYN_STREAM frame with incorrect length %uz",
+ sc->length);
+
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -964,7 +972,7 @@ ngx_http_spdy_state_syn_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
if (sc->processing >= sscf->concurrent_streams) {
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
- "spdy concurrent streams exceeded %ui", sc->processing);
+ "concurrent streams exceeded %ui", sc->processing);
if (ngx_http_spdy_send_rst_stream(sc, sid, NGX_SPDY_REFUSED_STREAM,
prio)
@@ -1001,7 +1009,6 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
size_t size;
ngx_buf_t *buf;
ngx_int_t rc;
- ngx_uint_t complete;
ngx_http_request_t *r;
size = end - pos;
@@ -1011,18 +1018,14 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_http_spdy_state_headers);
}
- if (size >= sc->length) {
+ if (size > sc->length) {
size = sc->length;
- complete = 1;
-
- } else {
- complete = 0;
}
r = sc->stream->request;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy process HEADERS %uz of %uz", size, sc->length);
+ "process spdy header block %uz of %uz", size, sc->length);
buf = r->header_in;
@@ -1038,11 +1041,21 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
if (z == Z_NEED_DICT) {
z = inflateSetDictionary(&sc->zstream_in, ngx_http_spdy_dict,
sizeof(ngx_http_spdy_dict));
+
if (z != Z_OK) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "spdy inflateSetDictionary() failed: %d", z);
- ngx_http_spdy_close_stream(sc->stream, 0);
- return ngx_http_spdy_state_protocol_error(sc);
+ if (z == Z_DATA_ERROR) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent SYN_STREAM frame with header "
+ "block encoded using wrong dictionary: %ul",
+ (u_long) sc->zstream_in.adler);
+
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "inflateSetDictionary() failed: %d", z);
+
+ return ngx_http_spdy_state_internal_error(sc);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1053,10 +1066,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
}
if (z != Z_OK) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "spdy inflate() failed: %d", z);
- ngx_http_spdy_close_stream(sc->stream, 0);
- return ngx_http_spdy_state_protocol_error(sc);
+ return ngx_http_spdy_state_inflate_error(sc, z);
}
ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1074,12 +1084,11 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
if (buf->last - buf->pos < NGX_SPDY_NV_NUM_SIZE) {
- if (complete) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent SYN_STREAM frame "
- "with invalid HEADERS block");
- ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
- return ngx_http_spdy_state_protocol_error(sc);
+ if (sc->length == 0) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "premature end of spdy header block");
+
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
}
return ngx_http_spdy_state_save(sc, pos, end,
@@ -1091,7 +1100,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
buf->pos += NGX_SPDY_NV_NUM_SIZE;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy HEADERS block consists of %ui entries",
+ "spdy header block has %ui entries",
sc->entries);
if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
@@ -1100,7 +1109,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
{
ngx_http_spdy_close_stream(sc->stream,
NGX_HTTP_INTERNAL_SERVER_ERROR);
- return ngx_http_spdy_state_headers_error(sc, pos, end);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
}
if (ngx_array_init(&r->headers_in.cookies, r->pool, 2,
@@ -1109,7 +1118,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
{
ngx_http_spdy_close_stream(sc->stream,
NGX_HTTP_INTERNAL_SERVER_ERROR);
- return ngx_http_spdy_state_headers_error(sc, pos, end);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
}
}
@@ -1132,16 +1141,15 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
rc = ngx_http_spdy_alloc_large_header_buffer(r);
if (rc == NGX_DECLINED) {
- /* TODO logging */
ngx_http_finalize_request(r,
NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
- return ngx_http_spdy_state_headers_error(sc, pos, end);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
}
if (rc != NGX_OK) {
ngx_http_spdy_close_stream(sc->stream,
NGX_HTTP_INTERNAL_SERVER_ERROR);
- return ngx_http_spdy_state_headers_error(sc, pos, end);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
}
/* null-terminate the last processed header name or value */
@@ -1157,10 +1165,7 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
z = inflate(&sc->zstream_in, Z_NO_FLUSH);
if (z != Z_OK) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "spdy inflate() failed: %d", z);
- ngx_http_spdy_close_stream(sc->stream, 0);
- return ngx_http_spdy_state_protocol_error(sc);
+ return ngx_http_spdy_state_inflate_error(sc, z);
}
sc->length -= sc->zstream_in.next_in - pos;
@@ -1171,33 +1176,22 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
continue;
}
- if (complete) {
- /* TODO: improve error message */
+ if (sc->length == 0) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy again while last chunk");
- ngx_http_spdy_close_stream(sc->stream, 0);
- return ngx_http_spdy_state_protocol_error(sc);
+ "premature end of spdy header block");
+
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
}
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_headers);
- case NGX_HTTP_PARSE_INVALID_REQUEST:
-
- /* TODO: improve error message */
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent invalid header line");
-
+ case NGX_HTTP_PARSE_INVALID_HEADER:
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
+ default: /* NGX_ERROR */
return ngx_http_spdy_state_headers_error(sc, pos, end);
-
- default: /* NGX_HTTP_PARSE_INVALID_HEADER */
-
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent invalid HEADERS spdy frame");
- ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
- return ngx_http_spdy_state_protocol_error(sc);
}
/* a header line has been parsed successfully */
@@ -1206,29 +1200,27 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
if (rc != NGX_OK) {
if (rc == NGX_HTTP_PARSE_INVALID_HEADER) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent invalid HEADERS spdy frame");
- ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
- return ngx_http_spdy_state_protocol_error(sc);
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
}
- if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) {
- ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ if (rc != NGX_ABORT) {
+ ngx_http_spdy_close_stream(sc->stream,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
}
- return ngx_http_spdy_state_headers_error(sc, pos, end);
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
}
}
if (buf->pos != buf->last || sc->zstream_in.avail_in) {
- ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent SYN_STREAM frame "
- "with invalid HEADERS block");
- ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
- return ngx_http_spdy_state_protocol_error(sc);
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "incorrect number of spdy header block entries");
+
+ return ngx_http_spdy_state_headers_error(sc, pos, end);
}
- if (!complete) {
+ if (sc->length) {
return ngx_http_spdy_state_save(sc, pos, end,
ngx_http_spdy_state_headers);
}
@@ -1243,18 +1235,6 @@ ngx_http_spdy_state_headers(ngx_http_spdy_connection_t *sc, u_char *pos,
static u_char *
-ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
- u_char *end)
-{
- if (sc->connection->error) {
- return ngx_http_spdy_state_internal_error(sc);
- }
-
- return ngx_http_spdy_state_headers_skip(sc, pos, end);
-}
-
-
-static u_char *
ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
@@ -1273,6 +1253,9 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_http_spdy_state_headers_skip);
}
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy header block skip %uz of %uz", size, sc->length);
+
sc->zstream_in.next_in = pos;
sc->zstream_in.avail_in = (size < sc->length) ? size : sc->length;
@@ -1282,12 +1265,8 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
n = inflate(&sc->zstream_in, Z_NO_FLUSH);
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy inflate(): %d", n);
-
if (n != Z_OK) {
- /* TODO: logging */
- return ngx_http_spdy_state_protocol_error(sc);
+ return ngx_http_spdy_state_inflate_error(sc, n);
}
}
@@ -1304,6 +1283,33 @@ ngx_http_spdy_state_headers_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
static u_char *
+ngx_http_spdy_state_headers_error(ngx_http_spdy_connection_t *sc, u_char *pos,
+ u_char *end)
+{
+ ngx_http_spdy_stream_t *stream;
+
+ stream = sc->stream;
+
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent SYN_STREAM frame for stream %ui "
+ "with invalid header block", stream->id);
+
+ if (ngx_http_spdy_send_rst_stream(sc, stream->id, NGX_SPDY_PROTOCOL_ERROR,
+ stream->priority)
+ != NGX_OK)
+ {
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
+ stream->out_closed = 1;
+
+ ngx_http_spdy_close_stream(stream, NGX_HTTP_BAD_REQUEST);
+
+ return ngx_http_spdy_state_headers_skip(sc, pos, end);
+}
+
+
+static u_char *
ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
@@ -1352,7 +1358,7 @@ ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
"client violated flow control for stream %ui: "
"received WINDOW_UPDATE frame with delta %uz "
- "that is not allowed for window %z",
+ "not allowed for window %z",
sid, delta, stream->send_window);
if (ngx_http_spdy_terminate_stream(sc, stream,
@@ -1385,7 +1391,7 @@ ngx_http_spdy_state_window_update(ngx_http_spdy_connection_t *sc, u_char *pos,
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
"client violated connection flow control: "
"received WINDOW_UPDATE frame with delta %uz "
- "that is not allowed for window %uz",
+ "not allowed for window %uz",
delta, sc->send_window);
return ngx_http_spdy_state_protocol_error(sc);
@@ -1428,8 +1434,8 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
if (sc->length > sc->recv_window) {
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
- "client violated connection flow control: length of "
- "received DATA frame %uz, while available window %uz",
+ "client violated connection flow control: "
+ "received DATA frame length %uz, available window %uz",
sc->length, sc->recv_window);
return ngx_http_spdy_state_protocol_error(sc);
@@ -1453,13 +1459,16 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
stream = sc->stream;
if (stream == NULL) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "unknown spdy stream");
+
return ngx_http_spdy_state_skip(sc, pos, end);
}
if (sc->length > stream->recv_window) {
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
- "client violated flow control for stream %ui: length of "
- "received DATA frame %uz, while available window %uz",
+ "client violated flow control for stream %ui: "
+ "received DATA frame length %uz, available window %uz",
stream->id, sc->length, stream->recv_window);
if (ngx_http_spdy_terminate_stream(sc, stream,
@@ -1489,7 +1498,7 @@ ngx_http_spdy_state_data(ngx_http_spdy_connection_t *sc, u_char *pos,
if (stream->in_closed) {
ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
- "client sent DATA frame for half closed stream %ui",
+ "client sent DATA frame for half-closed stream %ui",
stream->id);
if (ngx_http_spdy_terminate_stream(sc, stream,
@@ -1532,7 +1541,10 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
stream->in_closed = 1;
}
- /* TODO log and accounting */
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "skipping spdy DATA frame, reason: %d",
+ stream->skip_data);
+
return ngx_http_spdy_state_skip(sc, pos, end);
}
@@ -1561,7 +1573,10 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
if (r->headers_in.content_length_n != -1
&& r->headers_in.content_length_n < rb->rest)
{
- /* TODO logging */
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client intended to send body data "
+ "larger than declared");
+
stream->skip_data = NGX_SPDY_DATA_ERROR;
goto error;
@@ -1572,9 +1587,8 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
&& clcf->client_max_body_size < rb->rest)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "client intended to send too large chunked "
- "body: %O bytes",
- rb->rest);
+ "client intended to send "
+ "too large chunked body: %O bytes", rb->rest);
stream->skip_data = NGX_SPDY_DATA_ERROR;
goto error;
@@ -1626,7 +1640,7 @@ ngx_http_spdy_state_read_data(ngx_http_spdy_connection_t *sc, u_char *pos,
} else if (r->headers_in.content_length_n != rb->rest) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client prematurely closed stream: "
- "%O of %O bytes of request body received",
+ "only %O out of %O bytes of request body received",
rb->rest, r->headers_in.content_length_n);
stream->skip_data = NGX_SPDY_DATA_ERROR;
@@ -1705,9 +1719,11 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
"spdy RST_STREAM sid:%ui st:%ui", sid, status);
stream = ngx_http_spdy_get_stream_by_id(sc, sid);
+
if (stream == NULL) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "unknown stream, probably it has been closed already");
+ "unknown spdy stream");
+
return ngx_http_spdy_state_complete(sc, pos, end);
}
@@ -1726,7 +1742,7 @@ ngx_http_spdy_state_rst_stream(ngx_http_spdy_connection_t *sc, u_char *pos,
case NGX_SPDY_INTERNAL_ERROR:
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
- "client terminated stream %ui because of internal error",
+ "client terminated stream %ui due to internal error",
sid);
break;
@@ -1758,7 +1774,10 @@ ngx_http_spdy_state_ping(ngx_http_spdy_connection_t *sc, u_char *pos,
}
if (sc->length != NGX_SPDY_PING_SIZE) {
- /* TODO logging */
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent PING frame with incorrect length %uz",
+ sc->length);
+
return ngx_http_spdy_state_protocol_error(sc);
}
@@ -1798,6 +1817,9 @@ ngx_http_spdy_state_skip(ngx_http_spdy_connection_t *sc, u_char *pos,
size = end - pos;
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy frame skip %uz of %uz", size, sc->length);
+
if (size < sc->length) {
sc->length -= size;
return ngx_http_spdy_state_save(sc, end, end,
@@ -1827,13 +1849,16 @@ ngx_http_spdy_state_settings(ngx_http_spdy_connection_t *sc, u_char *pos,
sc->length -= NGX_SPDY_SETTINGS_NUM_SIZE;
if (sc->length < sc->entries * NGX_SPDY_SETTINGS_PAIR_SIZE) {
- /* TODO logging */
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent SETTINGS frame with incorrect "
+ "length %uz or number of entries %ui",
+ sc->length, sc->entries);
+
return ngx_http_spdy_state_protocol_error(sc);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy SETTINGS frame consists of %ui entries",
- sc->entries);
+ "spdy SETTINGS frame has %ui entries", sc->entries);
}
while (sc->entries) {
@@ -1893,7 +1918,20 @@ static u_char *
ngx_http_spdy_state_complete(ngx_http_spdy_connection_t *sc, u_char *pos,
u_char *end)
{
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy frame complete pos:%p end:%p", pos, end);
+
+ if (pos > end) {
+ ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
+ "receive buffer overrun");
+
+ ngx_debug_point();
+ return ngx_http_spdy_state_internal_error(sc);
+ }
+
sc->handler = ngx_http_spdy_state_head;
+ sc->stream = NULL;
+
return pos;
}
@@ -1904,12 +1942,17 @@ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
{
size_t size;
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
+ "spdy frame state save pos:%p end:%p handler:%p",
+ pos, end, handler);
+
size = end - pos;
if (size > NGX_SPDY_STATE_BUFFER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
- "spdy state buffer overflow: "
- "%uz bytes required", size);
+ "state buffer overflow: %uz bytes required", size);
+
+ ngx_debug_point();
return ngx_http_spdy_state_internal_error(sc);
}
@@ -1924,13 +1967,36 @@ ngx_http_spdy_state_save(ngx_http_spdy_connection_t *sc,
static u_char *
+ngx_http_spdy_state_inflate_error(ngx_http_spdy_connection_t *sc, int rc)
+{
+ if (rc == Z_DATA_ERROR || rc == Z_STREAM_END) {
+ ngx_log_error(NGX_LOG_INFO, sc->connection->log, 0,
+ "client sent SYN_STREAM frame with "
+ "corrupted header block, inflate() failed: %d", rc);
+
+ return ngx_http_spdy_state_protocol_error(sc);
+ }
+
+ ngx_log_error(NGX_LOG_ERR, sc->connection->log, 0,
+ "inflate() failed: %d", rc);
+
+ return ngx_http_spdy_state_internal_error(sc);
+}
+
+
+static u_char *
ngx_http_spdy_state_protocol_error(ngx_http_spdy_connection_t *sc)
{
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy state protocol error");
- /* TODO */
+ if (sc->stream) {
+ sc->stream->out_closed = 1;
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_BAD_REQUEST);
+ }
+
ngx_http_spdy_finalize_connection(sc, NGX_HTTP_CLIENT_CLOSED_REQUEST);
+
return NULL;
}
@@ -1941,8 +2007,13 @@ ngx_http_spdy_state_internal_error(ngx_http_spdy_connection_t *sc)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
"spdy state internal error");
- /* TODO */
+ if (sc->stream) {
+ sc->stream->out_closed = 1;
+ ngx_http_spdy_close_stream(sc->stream, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ }
+
ngx_http_spdy_finalize_connection(sc, NGX_HTTP_INTERNAL_SERVER_ERROR);
+
return NULL;
}
@@ -1956,7 +2027,7 @@ ngx_http_spdy_send_window_update(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
ngx_http_spdy_out_frame_t *frame;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy write WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
+ "spdy send WINDOW_UPDATE sid:%ui delta:%ui", sid, delta);
frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_WINDOW_UPDATE_SIZE,
NGX_SPDY_HIGHEST_PRIORITY);
@@ -1995,7 +2066,7 @@ ngx_http_spdy_send_rst_stream(ngx_http_spdy_connection_t *sc, ngx_uint_t sid,
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy write RST_STREAM sid:%ui st:%ui", sid, status);
+ "spdy send RST_STREAM sid:%ui st:%ui", sid, status);
frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_RST_STREAM_SIZE,
priority);
@@ -2030,7 +2101,7 @@ ngx_http_spdy_send_goaway(ngx_http_spdy_connection_t *sc)
ngx_http_spdy_out_frame_t *frame;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy create GOAWAY sid:%ui", sc->last_sid);
+ "spdy send GOAWAY sid:%ui", sc->last_sid);
frame = ngx_http_spdy_get_ctl_frame(sc, NGX_SPDY_GOAWAY_SIZE,
NGX_SPDY_HIGHEST_PRIORITY);
@@ -2066,7 +2137,7 @@ ngx_http_spdy_send_settings(ngx_http_spdy_connection_t *sc)
ngx_http_spdy_out_frame_t *frame;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
- "spdy create SETTINGS frame");
+ "spdy send SETTINGS frame");
frame = ngx_palloc(sc->pool, sizeof(ngx_http_spdy_out_frame_t));
if (frame == NULL) {
@@ -2188,7 +2259,7 @@ ngx_http_spdy_get_ctl_frame(ngx_http_spdy_connection_t *sc, size_t length,
#if (NGX_DEBUG)
if (length > NGX_SPDY_CTL_FRAME_BUFFER_SIZE - NGX_SPDY_FRAME_HEADER_SIZE) {
ngx_log_error(NGX_LOG_ALERT, sc->pool->log, 0,
- "requested control frame is too big: %uz", length);
+ "requested control frame is too large: %uz", length);
return NULL;
}
@@ -2406,7 +2477,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
r->lowcase_index = ngx_spdy_frame_parse_uint32(p);
if (r->lowcase_index == 0) {
- return NGX_HTTP_PARSE_INVALID_HEADER;
+ return NGX_ERROR;
}
/* null-terminate the previous header value */
@@ -2456,11 +2527,15 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
case LF:
case CR:
case ':':
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid header name: \"%*s\"",
+ r->lowcase_index, r->header_name_start);
+
+ return NGX_HTTP_PARSE_INVALID_HEADER;
}
if (ch >= 'A' && ch <= 'Z') {
- return NGX_HTTP_PARSE_INVALID_HEADER;
+ return NGX_ERROR;
}
r->invalid_header = 1;
@@ -2513,6 +2588,15 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
}
if (ch == CR || ch == LF) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent header \"%*s\" with "
+ "invalid value: \"%*s\\%c...\"",
+ r->header_name_end - r->header_name_start,
+ r->header_name_start,
+ p - r->header_start,
+ r->header_start,
+ ch == CR ? 'r' : 'n');
+
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -2537,7 +2621,7 @@ ngx_http_spdy_parse_header(ngx_http_request_t *r)
static ngx_int_t
ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
{
- u_char *old, *new;
+ u_char *old, *new, *p;
size_t rest;
ngx_buf_t *buf;
ngx_http_spdy_stream_t *stream;
@@ -2553,12 +2637,30 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
if (stream->header_buffers
== (ngx_uint_t) cscf->large_client_header_buffers.num)
{
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent too large request");
+
return NGX_DECLINED;
}
rest = r->header_in->last - r->header_in->pos;
+ /*
+ * equality is prohibited since one more byte is needed
+ * for null-termination
+ */
if (rest >= cscf->large_client_header_buffers.size) {
+ p = r->header_in->pos;
+
+ if (rest > NGX_MAX_ERROR_STR - 300) {
+ rest = NGX_MAX_ERROR_STR - 300;
+ p[rest++] = '.'; p[rest++] = '.'; p[rest++] = '.';
+ }
+
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent too long header name or value: \"%*s\"",
+ rest, p);
+
return NGX_DECLINED;
}
@@ -2568,7 +2670,7 @@ ngx_http_spdy_alloc_large_header_buffer(ngx_http_request_t *r)
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "spdy large header alloc: %p %z",
+ "spdy large header alloc: %p %uz",
buf->pos, buf->end - buf->last);
old = r->header_in->pos;
@@ -2623,13 +2725,16 @@ ngx_http_spdy_handle_request_header(ngx_http_request_t *r)
return sh->handler(r);
}
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid header name: \":%*s\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start);
+
+ return NGX_HTTP_PARSE_INVALID_HEADER;
}
h = ngx_list_push(&r->headers_in.headers);
if (h == NULL) {
- ngx_http_spdy_close_stream(r->spdy_stream,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_ERROR;
}
@@ -2695,6 +2800,9 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r)
}, *test;
if (r->method_name.len) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent duplicate :method header");
+
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -2732,8 +2840,10 @@ ngx_http_spdy_parse_method(ngx_http_request_t *r)
do {
if ((*p < 'A' || *p > 'Z') && *p != '_') {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
- "client sent invalid method");
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ "client sent invalid method: \"%V\"",
+ &r->method_name);
+
+ return NGX_HTTP_PARSE_INVALID_HEADER;
}
p++;
@@ -2748,6 +2858,9 @@ static ngx_int_t
ngx_http_spdy_parse_scheme(ngx_http_request_t *r)
{
if (r->schema_start) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent duplicate :schema header");
+
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -2764,13 +2877,14 @@ ngx_http_spdy_parse_host(ngx_http_request_t *r)
ngx_table_elt_t *h;
if (r->headers_in.host) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent duplicate :host header");
+
return NGX_HTTP_PARSE_INVALID_HEADER;
}
h = ngx_list_push(&r->headers_in.headers);
if (h == NULL) {
- ngx_http_spdy_close_stream(r->spdy_stream,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_ERROR;
}
@@ -2794,6 +2908,9 @@ static ngx_int_t
ngx_http_spdy_parse_path(ngx_http_request_t *r)
{
if (r->unparsed_uri.len) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent duplicate :path header");
+
return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -2801,11 +2918,19 @@ ngx_http_spdy_parse_path(ngx_http_request_t *r)
r->uri_end = r->header_end;
if (ngx_http_parse_uri(r) != NGX_OK) {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid URI: \"%*s\"",
+ r->uri_end - r->uri_start, r->uri_start);
+
+ return NGX_HTTP_PARSE_INVALID_HEADER;
}
if (ngx_http_process_request_uri(r) != NGX_OK) {
- return NGX_ERROR;
+ /*
+ * request has been finalized already
+ * in ngx_http_process_request_uri()
+ */
+ return NGX_ABORT;
}
return NGX_OK;
@@ -2818,19 +2943,22 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
u_char *p, ch;
if (r->http_protocol.len) {
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent duplicate :version header");
+
return NGX_HTTP_PARSE_INVALID_HEADER;
}
p = r->header_start;
if (r->header_end - p < 8 || !(ngx_str5cmp(p, 'H', 'T', 'T', 'P', '/'))) {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ goto invalid;
}
ch = *(p + 5);
if (ch < '1' || ch > '9') {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ goto invalid;
}
r->http_major = ch - '0';
@@ -2844,20 +2972,20 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
}
if (ch < '0' || ch > '9') {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ goto invalid;
}
r->http_major = r->http_major * 10 + ch - '0';
}
if (*p != '.') {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ goto invalid;
}
ch = *(p + 1);
if (ch < '0' || ch > '9') {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ goto invalid;
}
r->http_minor = ch - '0';
@@ -2867,7 +2995,7 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
ch = *p;
if (ch < '0' || ch > '9') {
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ goto invalid;
}
r->http_minor = r->http_minor * 10 + ch - '0';
@@ -2878,6 +3006,14 @@ ngx_http_spdy_parse_version(ngx_http_request_t *r)
r->http_version = r->http_major * 1000 + r->http_minor;
return NGX_OK;
+
+invalid:
+
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid http version: \"%*s\"",
+ r->header_end - r->header_start, r->header_start);
+
+ return NGX_HTTP_PARSE_INVALID_HEADER;
}
@@ -2900,7 +3036,8 @@ ngx_http_spdy_construct_request_line(ngx_http_request_t *r)
p = ngx_pnalloc(r->pool, r->request_line.len + 1);
if (p == NULL) {
- ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ ngx_http_spdy_close_stream(r->spdy_stream,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_ERROR;
}
@@ -2964,7 +3101,7 @@ ngx_http_spdy_run_request(ngx_http_request_t *r)
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http header: \"%V: %V\"", &h[i].key, &h[i].value);
+ "spdy http header: \"%V: %V\"", &h[i].key, &h[i].value);
}
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
@@ -3226,7 +3363,7 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
if (ev->active || ev->disabled) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
- "spdy fake read event was activated");
+ "fake read event was activated");
}
if (ev->timer_set) {
@@ -3241,7 +3378,7 @@ ngx_http_spdy_close_stream(ngx_http_spdy_stream_t *stream, ngx_int_t rc)
if (ev->active || ev->disabled) {
ngx_log_error(NGX_LOG_ALERT, sc->connection->log, 0,
- "spdy fake write event was activated");
+ "fake write event was activated");
}
if (ev->timer_set) {
diff --git a/src/http/ngx_http_spdy_filter_module.c b/src/http/ngx_http_spdy_filter_module.c
index 559fb4aab..82405d9a1 100644
--- a/src/http/ngx_http_spdy_filter_module.c
+++ b/src/http/ngx_http_spdy_filter_module.c
@@ -533,8 +533,7 @@ ngx_http_spdy_header_filter(ngx_http_request_t *r)
ngx_free(buf);
if (rc != Z_OK) {
- ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "spdy deflate() failed: %d", rc);
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0, "deflate() failed: %d", rc);
return NGX_ERROR;
}
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index af77e50e7..de3ff130a 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -216,7 +216,8 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_rewrite_refresh, 0, 0 },
{ ngx_string("Set-Cookie"),
- ngx_http_upstream_process_set_cookie, 0,
+ ngx_http_upstream_process_set_cookie,
+ offsetof(ngx_http_upstream_headers_in_t, cookies),
ngx_http_upstream_rewrite_set_cookie, 0, 1 },
{ ngx_string("Content-Disposition"),
@@ -583,9 +584,6 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
if (u->resolved == NULL) {
uscf = u->conf->upstream;
-#if (NGX_HTTP_SSL)
- u->ssl_name = uscf->host;
-#endif
} else {
@@ -679,6 +677,10 @@ found:
return;
}
+#if (NGX_HTTP_SSL)
+ u->ssl_name = uscf->host;
+#endif
+
if (uscf->peer.init(r, uscf) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
@@ -3731,11 +3733,28 @@ static ngx_int_t
ngx_http_upstream_process_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
-#if (NGX_HTTP_CACHE)
- ngx_http_upstream_t *u;
+ ngx_array_t *pa;
+ ngx_table_elt_t **ph;
+ ngx_http_upstream_t *u;
u = r->upstream;
+ pa = &u->headers_in.cookies;
+ if (pa->elts == NULL) {
+ if (ngx_array_init(pa, r->pool, 1, sizeof(ngx_table_elt_t *)) != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+ }
+
+ ph = ngx_array_push(pa);
+ if (ph == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ph = h;
+
+#if (NGX_HTTP_CACHE)
if (!(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_SET_COOKIE)) {
u->cacheable = 0;
}
@@ -4657,6 +4676,40 @@ ngx_http_upstream_header_variable(ngx_http_request_t *r,
}
+ngx_int_t
+ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ ngx_str_t *name = (ngx_str_t *) data;
+
+ ngx_str_t cookie, s;
+
+ if (r->upstream == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ s.len = name->len - (sizeof("upstream_cookie_") - 1);
+ s.data = name->data + sizeof("upstream_cookie_") - 1;
+
+ if (ngx_http_parse_set_cookie_lines(&r->upstream->headers_in.cookies,
+ &s, &cookie)
+ == NGX_DECLINED)
+ {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->len = cookie.len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = cookie.data;
+
+ return NGX_OK;
+}
+
+
#if (NGX_HTTP_CACHE)
ngx_int_t
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index b8998ced8..50b3e6367 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -248,6 +248,7 @@ typedef struct {
off_t content_length_n;
ngx_array_t cache_control;
+ ngx_array_t cookies;
unsigned connection_close:1;
unsigned chunked:1;
@@ -363,6 +364,8 @@ typedef struct {
} ngx_http_upstream_param_t;
+ngx_int_t ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index f61862297..1b61c39d4 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -13,8 +13,10 @@
static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+#if 0
static void ngx_http_variable_request_set(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+#endif
static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
@@ -64,6 +66,8 @@ static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_https(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static void ngx_http_variable_set_args(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
@@ -223,7 +227,7 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
NGX_HTTP_VAR_NOCACHEABLE, 0 },
{ ngx_string("args"),
- ngx_http_variable_request_set,
+ ngx_http_variable_set_args,
ngx_http_variable_request,
offsetof(ngx_http_request_t, args),
NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
@@ -613,6 +617,17 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
return NULL;
}
+ if (ngx_strncmp(name->data, "upstream_cookie_", 16) == 0) {
+
+ if (ngx_http_upstream_cookie_variable(r, vv, (uintptr_t) name)
+ == NGX_OK)
+ {
+ return vv;
+ }
+
+ return NULL;
+ }
+
if (ngx_strncmp(name->data, "arg_", 4) == 0) {
if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
@@ -651,6 +666,8 @@ ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
}
+#if 0
+
static void
ngx_http_variable_request_set(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
@@ -663,6 +680,8 @@ ngx_http_variable_request_set(ngx_http_request_t *r,
s->data = v->data;
}
+#endif
+
static ngx_int_t
ngx_http_variable_request_get_size(ngx_http_request_t *r,
@@ -1360,6 +1379,16 @@ ngx_http_variable_https(ngx_http_request_t *r,
}
+static void
+ngx_http_variable_set_args(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ r->args.len = v->len;
+ r->args.data = v->data;
+ r->valid_unparsed_uri = 0;
+}
+
+
static ngx_int_t
ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
@@ -2528,6 +2557,14 @@ ngx_http_variables_init_vars(ngx_conf_t *cf)
continue;
}
+ if (ngx_strncmp(v[i].name.data, "upstream_cookie_", 16) == 0) {
+ v[i].get_handler = ngx_http_upstream_cookie_variable;
+ v[i].data = (uintptr_t) &v[i].name;
+ v[i].flags = NGX_HTTP_VAR_NOCACHEABLE;
+
+ continue;
+ }
+
if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
v[i].get_handler = ngx_http_variable_argument;
v[i].data = (uintptr_t) &v[i].name;
diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c
index 8094bbc5c..eb7531c80 100644
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1269,7 +1269,7 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
l.len = b->last - b->pos;
l.data = b->pos;
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
- "mail auth http header:\n\"%V\"", &l);
+ "mail auth http header:%N\"%V\"", &l);
}
#endif
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c
index 47ddb0dcf..784111f6e 100644
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -22,6 +22,7 @@ static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c);
void
ngx_mail_init_connection(ngx_connection_t *c)
{
+ size_t len;
ngx_uint_t i;
ngx_mail_port_t *port;
struct sockaddr *sa;
@@ -30,6 +31,7 @@ ngx_mail_init_connection(ngx_connection_t *c)
ngx_mail_in_addr_t *addr;
ngx_mail_session_t *s;
ngx_mail_addr_conf_t *addr_conf;
+ u_char text[NGX_SOCKADDR_STRLEN];
#if (NGX_HAVE_INET6)
struct sockaddr_in6 *sin6;
ngx_mail_in6_addr_t *addr6;
@@ -127,8 +129,10 @@ ngx_mail_init_connection(ngx_connection_t *c)
c->data = s;
s->connection = c;
- ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %V connected to %V",
- c->number, &c->addr_text, s->addr_text);
+ len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);
+
+ ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
+ c->number, len, text, s->addr_text);
ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
if (ctx == NULL) {
diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c
index 52fe47523..665f5ef19 100644
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -679,6 +679,11 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
return NGX_OK;
}
+ if (s->args.nelts == 0) {
+ ngx_str_set(&s->out, smtp_invalid_argument);
+ return NGX_OK;
+ }
+
arg = s->args.elts;
arg += s->args.nelts - 1;
@@ -713,6 +718,11 @@ ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
return NGX_OK;
}
+ if (s->args.nelts == 0) {
+ ngx_str_set(&s->out, smtp_invalid_argument);
+ return NGX_OK;
+ }
+
arg = s->args.elts;
arg += s->args.nelts - 1;
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
index 72594bac0..c6c02c93e 100644
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -94,6 +94,9 @@ extern ssize_t sendfile(int s, int fd, int32_t *offset, size_t size);
#if (NGX_HAVE_FILE_AIO)
+#if (NGX_HAVE_SYS_EVENTFD_H)
+#include <sys/eventfd.h>
+#endif
#include <sys/syscall.h>
#include <linux/aio_abi.h>
typedef struct iocb ngx_aiocb_t;
diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c
index 58e6f7614..9a4de022d 100644
--- a/src/os/unix/ngx_posix_init.c
+++ b/src/os/unix/ngx_posix_init.c
@@ -82,7 +82,7 @@ ngx_os_init(ngx_log_t *log)
void
ngx_os_status(ngx_log_t *log)
{
- ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER);
+ ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER_BUILD);
#ifdef NGX_COMPILER
ngx_log_error(NGX_LOG_NOTICE, log, 0, "built by " NGX_COMPILER);
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index be55cea20..fb10d7746 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -710,11 +710,13 @@ ngx_master_process_exit(ngx_cycle_t *cycle)
* ngx_cycle->pool is already destroyed.
*/
- ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
- ngx_exit_log = *ngx_cycle->log;
+ ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log);
+
+ ngx_exit_log_file.fd = ngx_exit_log.file->fd;
ngx_exit_log.file = &ngx_exit_log_file;
ngx_exit_log.next = NULL;
+ ngx_exit_log.writer = NULL;
ngx_exit_cycle.log = &ngx_exit_log;
ngx_exit_cycle.files = ngx_cycle->files;
@@ -1065,11 +1067,12 @@ ngx_worker_process_exit(ngx_cycle_t *cycle)
* ngx_cycle->pool is already destroyed.
*/
- ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
+ ngx_exit_log = *ngx_log_get_file_log(ngx_cycle->log);
- ngx_exit_log = *ngx_cycle->log;
+ ngx_exit_log_file.fd = ngx_exit_log.file->fd;
ngx_exit_log.file = &ngx_exit_log_file;
ngx_exit_log.next = NULL;
+ ngx_exit_log.writer = NULL;
ngx_exit_cycle.log = &ngx_exit_log;
ngx_exit_cycle.files = ngx_cycle->files;