diff options
author | nginx <nginx@nginx.org> | 2014-05-27 14:08:36 +0000 |
---|---|---|
committer | Jon Kolb <kolbyjack@gmail.com> | 2014-05-27 14:08:36 +0000 |
commit | b72398c9a386f5100c857869af10a910d97549fe (patch) | |
tree | fb57fd6f2ab1b365af5f13f82058b43614c80414 | |
parent | 7a8cd938c2c573a382568055e17e2a397c508b68 (diff) | |
download | nginx-1.7.1.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.
46 files changed, 1251 insertions, 252 deletions
@@ -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 @@ -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 @@ -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; |