# HG changeset patch # User Igor Sysoev # Date 1205269200 -10800 # Node ID babd3d9efb625a2afe53f106195370bd9d5467ca # Parent 9b0140fa113279f95e506c4f1c0bd2d9b92c1bd1 nginx 0.6.27 *) Change: now by default the rtsig method is not built on Linux 2.6.18+. *) Change: now a request method is not changed while redirection to a named location via an "error_page" directive. *) Feature: the "resolver" and "resolver_timeout" directives in SMTP proxy. *) Feature: the "post_action" directive supports named locations. *) Bugfix: a segmentation fault occurred in worker process, if a request was redirected from proxy, FastCGI, or memcached location to static named locations. *) Bugfix: browsers did not repeat SSL handshake if there is no valid client certificate in first handshake. Thanks to Alexander V. Inyukhin. *) Bugfix: if response code 495-497 was redirected via an "error_page" directive without code change, then nginx tried to allocate too many memory. *) Bugfix: memory leak in long-lived non buffered connections. *) Bugfix: memory leak in resolver. *) Bugfix: a segmentation fault occurred in worker process, if a request was redirected from proxy, FastCGI, or memcached location to static named locations. *) Bugfix: in the $proxy_host and $proxy_port variables caching. Thanks to Sergey Bochenkov. *) Bugfix: a "proxy_pass" directive with variables used incorrectly the same port as in another "proxy_pass" directive with the same host name and without variables. Thanks to Sergey Bochenkov. *) Bugfix: an alert "sendmsg() failed (9: Bad file descriptor)" on some 64-bit platforms while reconfiguration. *) Bugfix: a segmentation fault occurred in worker process, if empty stub block was used second time in SSI. *) Bugfix: in copying URI part contained escaped symbols into arguments. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,54 @@ +Changes with nginx 0.6.27 12 Mar 2008 + + *) Change: now by default the rtsig method is not built on + Linux 2.6.18+. + + *) Change: now a request method is not changed while redirection to a + named location via an "error_page" directive. + + *) Feature: the "resolver" and "resolver_timeout" directives in SMTP + proxy. + + *) Feature: the "post_action" directive supports named locations. + + *) Bugfix: a segmentation fault occurred in worker process, if a + request was redirected from proxy, FastCGI, or memcached location to + static named locations. + + *) Bugfix: browsers did not repeat SSL handshake if there is no valid + client certificate in first handshake. + Thanks to Alexander V. Inyukhin. + + *) Bugfix: if response code 495-497 was redirected via an "error_page" + directive without code change, then nginx tried to allocate too many + memory. + + *) Bugfix: memory leak in long-lived non buffered connections. + + *) Bugfix: memory leak in resolver. + + *) Bugfix: a segmentation fault occurred in worker process, if a + request was redirected from proxy, FastCGI, or memcached location to + static named locations. + + *) Bugfix: in the $proxy_host and $proxy_port variables caching. + Thanks to Sergey Bochenkov. + + *) Bugfix: a "proxy_pass" directive with variables used incorrectly the + same port as in another "proxy_pass" directive with the same host + name and without variables. + Thanks to Sergey Bochenkov. + + *) Bugfix: an alert "sendmsg() failed (9: Bad file descriptor)" on some + 64-bit platforms while reconfiguration. + + *) Bugfix: a segmentation fault occurred in worker process, if empty + stub block was used second time in SSI. + + *) Bugfix: in copying URI part contained escaped symbols into arguments. + + Changes with nginx 0.6.26 11 Feb 2008 *) Bugfix: the "proxy_store" and "fastcgi_store" directives did not diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,60 @@ +Изменения в nginx 0.6.27 12.03.2008 + + *) Изменение: теперь на Linux 2.6.18+ по умолчанию не собирается метод + rtsig. + + *) Изменение: теперь при перенаправлении запроса в именованный location + с помощью директивы error_page метод запроса не изменяется. + + *) Добавление: директивы resolver и resolver_timeout в SMTP + прокси-сервере. + + *) Добавление: директива post_action поддерживает именованные + location'ы. + + *) Исправление: при перенаправлении запроса из location'а c + обработчиком proxy, FastCGI или memcached в именованный location со + статическим обработчиком в рабочем процессе происходил segmentation + fault. + + *) Исправление: браузеры не повторяли SSL handshake, если при первом + handshake не оказалось правильного клиентского сертификата. + Спасибо Александру Инюхину. + + *) Исправление: при перенаправлении ошибок 495-497 с помощью директивы + error_page без изменения кода ошибки nginx пытался выделить очень + много памяти. + + *) Исправление: утечки памяти в долгоживущих небуфферизированных + соединениях. + + *) Исправление: утечки памяти в resolver'е. + + *) Исправление: при перенаправлении запроса из location'а c + обработчиком proxy в другой location с обработчиком proxy в рабочем + процессе происходил segmentation fault. + + *) Исправление: ошибки в кэшировании переменных $proxy_host и + $proxy_port. + Спасибо Сергею Боченкову. + + *) Исправление: директива proxy_pass с переменными использовала порт, + описанной в другой директиве proxy_pass без переменных, но с таким + же именем хоста. + Спасибо Сергею Боченкову. + + *) Исправление: во время переконфигурации на некоторых 64-битном + платформах в лог записывался alert "sendmsg() failed (9: Bad file + descriptor)". + + *) Исправление: при повторном использовании в SSI пустого block'а в + качестве заглушки в рабочем процессе происходил segmentation fault. + + *) Исправление: ошибки при копировании части URI, содержащего + экранированные символы, в аргументы. + + Изменения в nginx 0.6.26 11.02.2008 *) Исправление: директивы proxy_store и fastcgi_store не проверяли diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -16,18 +16,18 @@ CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURC # Linux kernel version -version=`grep "#define LINUX_VERSION_CODE" /usr/include/linux/version.h \ - | sed -e 's/^.* \(.*\)$/\1/'` +version=$((`uname -r \ + | sed 's/^\([^.]*\)\.\([^.]*\)\.\([^.-]*\).*/\1*256*256+\2*256+\3/'`)) version=${version:-0} -# enable the rt signals on Linux 2.2.19 and onward +# enable the rt signals on Linux between 2.2.19 and 2.6.17 -if [ $version -ge 131609 -o $EVENT_RTSIG = YES ]; then +if [ \( $version -ge 131603 -a $version -lt 132626 \) -o $EVENT_RTSIG = YES ] +then echo " + rt signals found" have=NGX_HAVE_RTSIG . auto/have - have=NGX_HAVE_POLL . auto/have EVENT_MODULES="$EVENT_MODULES $RTSIG_MODULE" CORE_SRCS="$CORE_SRCS $RTSIG_SRCS" EVENT_FOUND=YES diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -63,6 +63,7 @@ http { # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # #location ~ \.php$ { + # root html; # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.6.26" +#define NGINX_VERSION "0.6.27" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -633,7 +633,7 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com { char *rv; ngx_int_t n; - ngx_str_t *value, file; + ngx_str_t *value, file, name; ngx_glob_t gl; value = cf->args->elts; @@ -659,12 +659,15 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com rv = NGX_CONF_OK; for ( ;; ) { - n = ngx_read_glob(&gl, &file); + n = ngx_read_glob(&gl, &name); if (n != NGX_OK) { break; } + file.len = name.len++; + file.data = ngx_pstrdup(cf->pool, &name); + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); rv = ngx_conf_parse(cf, &file); diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -661,6 +661,8 @@ ngx_free_connection(ngx_connection_t *c) void ngx_close_connection(ngx_connection_t *c) { + ngx_err_t err; + ngx_uint_t log_error, level; ngx_socket_t fd; if (c->fd == -1) { @@ -733,6 +735,8 @@ ngx_close_connection(ngx_connection_t *c #endif + log_error = c->log_error; + ngx_free_connection(c); fd = c->fd; @@ -740,9 +744,31 @@ ngx_close_connection(ngx_connection_t *c if (ngx_close_socket(fd) == -1) { + err = ngx_socket_errno; + + if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) { + + switch (log_error) { + + case NGX_ERROR_INFO: + level = NGX_LOG_INFO; + break; + + case NGX_ERROR_ERR: + level = NGX_LOG_ERR; + break; + + default: + level = NGX_LOG_CRIT; + } + + } else { + level = NGX_LOG_CRIT; + } + /* we use ngx_cycle->log because c->log was in c->pool */ - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno, + ngx_log_error(level, ngx_cycle->log, err, ngx_close_socket_n " %d failed", fd); } } @@ -784,11 +810,11 @@ ngx_connection_error(ngx_connection_t *c break; default: - level = NGX_LOG_CRIT; + level = NGX_LOG_ALERT; } } else { - level = NGX_LOG_CRIT; + level = NGX_LOG_ALERT; } ngx_log_error(level, c->log, err, text); diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -554,7 +554,7 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ failed: - if (ext->delete) { + if (ext->delete_file) { if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, ngx_delete_file_n " \"%s\" failed", src->data); diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -63,7 +63,7 @@ typedef struct { ngx_fd_t fd; unsigned create_path:1; - unsigned delete:1; + unsigned delete_file:1; ngx_log_t *log; } ngx_ext_rename_file_t; diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -50,6 +50,8 @@ typedef struct { ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc); +static void ngx_resolver_cleanup(void *data); +static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree); static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx); static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, @@ -81,6 +83,7 @@ static ngx_int_t ngx_resolver_copy(ngx_r static void ngx_resolver_timeout_handler(ngx_event_t *ev); static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn); static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size); +static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size); static void ngx_resolver_free(ngx_resolver_t *r, void *p); static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p); static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size); @@ -89,17 +92,27 @@ static void *ngx_resolver_dup(ngx_resolv /* STUB: ngx_peer_addr_t * */ ngx_resolver_t * -ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log) +ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr) { ngx_resolver_t *r; + ngx_pool_cleanup_t *cln; ngx_udp_connection_t *uc; - r = ngx_calloc(sizeof(ngx_resolver_t), log); + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_resolver_cleanup; + + r = ngx_calloc(sizeof(ngx_resolver_t), cf->log); if (r == NULL) { return NULL; } - r->event = ngx_calloc(sizeof(ngx_event_t), log); + cln->data = r; + + r->event = ngx_calloc(sizeof(ngx_event_t), cf->log); if (r->event == NULL) { return NULL; } @@ -118,18 +131,18 @@ ngx_resolver_create(ngx_peer_addr_t *add r->event->handler = ngx_resolver_resend_handler; r->event->data = r; - r->event->log = log; + r->event->log = cf->cycle->new_log; r->ident = -1; r->resend_timeout = 5; r->expire = 30; r->valid = 300; - r->log = log; + r->log = cf->cycle->new_log; r->log_level = NGX_LOG_ALERT; if (addr) { - uc = ngx_calloc(sizeof(ngx_udp_connection_t), log); + uc = ngx_calloc(sizeof(ngx_udp_connection_t), cf->log); if (uc == NULL) { return NULL; } @@ -139,13 +152,72 @@ ngx_resolver_create(ngx_peer_addr_t *add uc->sockaddr = addr->sockaddr; uc->socklen = addr->socklen; uc->server = addr->name; - uc->log = log; + uc->log = cf->cycle->new_log; } return r; } +static void +ngx_resolver_cleanup(void *data) +{ + ngx_resolver_t *r = data; + + if (r) { + ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "cleanup resolver"); + + ngx_resolver_cleanup_tree(r, &r->name_rbtree); + + ngx_resolver_cleanup_tree(r, &r->addr_rbtree); + + if (r->event) { + ngx_free(r->event); + } + + if (r->udp_connection) { + if (r->udp_connection->connection) { + ngx_close_connection(r->udp_connection->connection); + } + + ngx_free(r->udp_connection); + } + + ngx_free(r); + } +} + + +static void +ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree) +{ + ngx_resolver_ctx_t *ctx, *next; + ngx_resolver_node_t *rn; + + while (tree->root != tree->sentinel) { + + rn = (ngx_resolver_node_t *) ngx_rbtree_min(tree->root, tree->sentinel); + + ngx_queue_remove(&rn->queue); + + for (ctx = rn->waiting; ctx; ctx = next) { + next = ctx->next; + + if (ctx->event) { + ngx_resolver_free(r, ctx->event); + } + + ngx_resolver_free(r, ctx); + } + + ngx_rbtree_delete(tree, &rn->node); + + ngx_resolver_free_node(r, rn); + } +} + + ngx_resolver_ctx_t * ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp) { @@ -211,14 +283,13 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx return NGX_OK; } - /* lock alloc mutex */ + /* NGX_ERROR */ if (ctx->event) { - ngx_resolver_free_locked(r, ctx->event); - ctx->event = NULL; + ngx_resolver_free(r, ctx->event); } - /* unlock alloc mutex */ + ngx_resolver_free(r, ctx); return NGX_ERROR; } @@ -279,7 +350,15 @@ done: /* unlock name mutex */ - ngx_resolver_free(r, ctx); + /* lock alloc mutex */ + + if (ctx->event) { + ngx_resolver_free_locked(r, ctx->event); + } + + ngx_resolver_free_locked(r, ctx); + + /* unlock alloc mutex */ } @@ -572,15 +651,11 @@ failed: /* unlock addr mutex */ - /* lock alloc mutex */ - if (ctx->event) { - ngx_resolver_free_locked(r, ctx->event); + ngx_resolver_free(r, ctx->event); } - ngx_resolver_free_locked(r, ctx); - - /* unlock alloc mutex */ + ngx_resolver_free(r, ctx); return NGX_ERROR; } @@ -639,7 +714,15 @@ done: /* unlock addr mutex */ - ngx_resolver_free(r, ctx); + /* lock alloc mutex */ + + if (ctx->event) { + ngx_resolver_free_locked(r, ctx->event); + } + + ngx_resolver_free_locked(r, ctx); + + /* unlock alloc mutex */ } @@ -695,6 +778,7 @@ ngx_resolver_send_query(ngx_resolver_t * uc->connection->data = r; uc->connection->read->handler = ngx_resolver_read_response; + uc->connection->read->resolver = 1; } n = ngx_send(uc->connection, rn->query, rn->qlen); @@ -1813,7 +1897,7 @@ ngx_resolver_alloc(ngx_resolver_t *r, si } -void * +static void * ngx_resolver_calloc(ngx_resolver_t *r, size_t size) { u_char *p; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -131,14 +131,13 @@ struct ngx_resolver_ctx_s { }; -ngx_resolver_t *ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log); +ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr); ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp); ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx); void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx); ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx); void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx); -void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size); char *ngx_resolver_strerror(ngx_int_t err); diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -136,6 +136,7 @@ struct ngx_event_s { /* to test on worker exit */ unsigned channel:1; + unsigned resolver:1; #if (NGX_THREADS) diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1552,6 +1552,15 @@ done: } +void +ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) +{ + SSL_CTX_remove_session(ssl, sess); + + ngx_ssl_remove_session(ssl, sess); +} + + static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) { @@ -1567,6 +1576,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index); + if (shm_zone == NULL) { + return; + } + cache = shm_zone->data; id = sess->session_id; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -105,6 +105,7 @@ ngx_int_t ngx_ssl_session_cache(ngx_ssl_ ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags); +void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); #define ngx_ssl_get_session(c) SSL_get1_session(c->ssl->connection) #define ngx_ssl_free_session SSL_SESSION_free diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -248,7 +248,7 @@ ngx_http_dav_put_handler(ngx_http_reques ext.access = dlcf->access; ext.time = -1; ext.create_path = dlcf->create_full_put_path; - ext.delete = 1; + ext.delete_file = 1; ext.log = r->connection->log; if (r->headers_in.date) { diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -461,6 +461,7 @@ ngx_http_memcached_filter(void *data, ss cl->buf->pos = last; b->last += bytes; cl->buf->last = b->last; + cl->buf->tag = u->output.tag; ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, "memcached filter bytes:%z size:%z length:%z rest:%z", diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -444,10 +444,10 @@ static ngx_str_t ngx_http_proxy_hide_he static ngx_http_variable_t ngx_http_proxy_vars[] = { { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0, - NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0, - NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOHASH, 0 }, + NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("proxy_add_x_forwarded_for"), NULL, ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, @@ -611,6 +611,7 @@ ngx_http_proxy_eval(ngx_http_request_t * r->upstream->resolved->host = u.host; r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port: u.port); + r->upstream->resolved->default_port = u.default_port; return NGX_OK; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -1983,6 +1983,7 @@ ngx_http_ssi_include(ngx_http_request_t if (bl[i].count++) { + out = NULL; ll = &out; for (tl = bl[i].bufs; tl; tl = tl->next) { diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.6.26'; +our $VERSION = '0.6.27'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -933,19 +933,24 @@ void sleep(r, sleep, next) CODE: - dXSTARG; ngx_http_request_t *r; + ngx_msec_t sleep; ngx_http_perl_ctx_t *ctx; ngx_http_perl_set_request(r); + sleep = (ngx_msec_t) SvIV(ST(1)); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "perl sleep: %M", sleep); + ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - ctx->sleep = SvIV(ST(1)); ctx->next = SvRV(ST(2)); - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "perl sleep: %d", ctx->sleep); + ngx_add_timer(r->connection->write, sleep); + + r->write_event_handler = ngx_http_perl_sleep_handler; void diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -41,7 +41,6 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params); #endif -static void ngx_http_perl_sleep_handler(ngx_http_request_t *r); static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf); static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf, @@ -49,7 +48,7 @@ static PerlInterpreter *ngx_http_perl_cr static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log); static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, - HV *nginx, SV *sub, ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv); + HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); @@ -252,12 +251,6 @@ ngx_http_perl_handle_request(ngx_http_re ctx->filename.data = NULL; ctx->redirect_uri.len = 0; - if (ctx->sleep) { - ngx_add_timer(r->connection->write, (ngx_msec_t) ctx->sleep); - r->write_event_handler = ngx_http_perl_sleep_handler; - ctx->sleep = 0; - } - if (ctx->done || ctx->next) { return; } @@ -276,7 +269,7 @@ ngx_http_perl_handle_request(ngx_http_re } -static void +void ngx_http_perl_sleep_handler(ngx_http_request_t *r) { ngx_event_t *wev; @@ -364,9 +357,10 @@ static ngx_int_t ngx_http_perl_ssi(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params) { - SV *sv; + SV *sv, **asv; ngx_int_t rc; - ngx_str_t *handler; + ngx_str_t *handler, **args; + ngx_uint_t i; ngx_http_perl_ctx_t *ctx; ngx_http_perl_main_conf_t *pmcf; @@ -416,9 +410,31 @@ ngx_http_perl_ssi(ngx_http_request_t *r, sv = newSVpvn((char *) handler->data, handler->len); - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, - ¶ms[NGX_HTTP_PERL_SSI_ARG], - handler, NULL); + args = ¶ms[NGX_HTTP_PERL_SSI_ARG]; + + if (args) { + + for (i = 0; args[i]; i++) { /* void */ } + + asv = ngx_pcalloc(r->pool, (i + 1) * sizeof(SV *)); + + if (asv == NULL) { + SvREFCNT_dec(sv); + return NGX_ERROR; + } + + asv[0] = (SV *) i; + + for (i = 0; args[i]; i++) { + asv[i + 1] = newSVpvn((char *) args[i]->data, args[i]->len); + } + + } else { + asv = NULL; + } + + rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, + NULL); SvREFCNT_dec(sv); @@ -629,7 +645,7 @@ ngx_http_perl_run_requires(pTHX_ ngx_arr static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, - ngx_str_t **args, ngx_str_t *handler, ngx_str_t *rv) + SV **args, ngx_str_t *handler, ngx_str_t *rv) { SV *sv; int n, status; @@ -652,12 +668,10 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt XPUSHs(sv); if (args) { - for (i = 0; args[i]; i++) { /* void */ } + EXTEND(sp, (int) args[0]); - EXTEND(sp, (int) i); - - for (i = 0; args[i]; i++) { - PUSHs(sv_2mortal(newSVpvn((char *) args[i]->data, args[i]->len))); + for (i = 1; i <= (ngx_uint_t) args[0]; i++) { + PUSHs(sv_2mortal(args[i])); } } diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h @@ -25,9 +25,8 @@ typedef struct { ngx_str_t redirect_args; SV *next; - int sleep; - ngx_uint_t done; /* unsigned done:1; */ + ngx_uint_t done; /* unsigned done:1; */ ngx_array_t *variables; /* array of ngx_http_perl_var_t */ @@ -61,6 +60,7 @@ extern void boot_DynaLoader(pTHX_ CV* cv void ngx_http_perl_handle_request(ngx_http_request_t *r); +void ngx_http_perl_sleep_handler(ngx_http_request_t *r); #endif /* _NGX_HTTP_PERL_MODULE_H_INCLUDED_ */ diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -551,7 +551,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (in_addr[a].default_server) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "the duplicate default server in %s:%ui", - &lscf[l].file_name, lscf[l].line); + lscf[l].file_name, lscf[l].line); return NGX_CONF_ERROR; } diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1916,7 +1916,7 @@ ngx_http_named_location(ngx_http_request "named location: %V \"%V?%V\"", name, &r->uri, &r->args); r->internal = 1; - + r->content_handler = NULL; r->loc_conf = clcfp[i]->loc_conf; ngx_http_update_location_config(r); @@ -1924,6 +1924,7 @@ ngx_http_named_location(ngx_http_request cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); r->phase_handler = cmcf->phase_engine.location_rewrite_index; + ngx_http_core_run_phases(r); return NGX_DONE; @@ -2907,14 +2908,21 @@ ngx_http_core_merge_loc_conf(ngx_conf_t prev->resolver_timeout, 30000); if (conf->resolver == NULL) { - conf->resolver = prev->resolver; - - if (conf->resolver == NULL) { - conf->resolver = ngx_resolver_create(NULL, cf->cycle->new_log); - if (conf->resolver == NULL) { + + if (prev->resolver == NULL) { + + /* + * create dummy resolver in http {} context + * to inherit it in all servers + */ + + prev->resolver = ngx_resolver_create(cf, NULL); + if (prev->resolver == NULL) { return NGX_CONF_ERROR; } } + + conf->resolver = prev->resolver; } ngx_conf_merge_path_value(conf->client_body_temp_path, @@ -3551,7 +3559,22 @@ ngx_http_core_error_page(ngx_conf_t *cf, return NGX_CONF_ERROR; } - err->overwrite = (overwrite >= 0) ? overwrite : err->status; + if (overwrite >= 0) { + err->overwrite = overwrite; + + } else { + switch (err->status) { + case NGX_HTTP_TO_HTTPS: + case NGX_HTTPS_CERT_ERROR: + case NGX_HTTPS_NO_CERT: + err->overwrite = NGX_HTTP_BAD_REQUEST; + break; + + default: + err->overwrite = err->status; + break; + } + } err->uri = uri; err->uri_lengths = uri_lengths; @@ -3716,6 +3739,10 @@ ngx_http_core_resolver(ngx_conf_t *cf, n ngx_url_t u; ngx_str_t *value; + if (clcf->resolver) { + return "is duplicate"; + } + value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); @@ -3728,7 +3755,7 @@ ngx_http_core_resolver(ngx_conf_t *cf, n return NGX_CONF_ERROR; } - clcf->resolver = ngx_resolver_create(&u.addrs[0], cf->cycle->new_log); + clcf->resolver = ngx_resolver_create(cf, &u.addrs[0]); if (clcf->resolver == NULL) { return NGX_OK; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1430,6 +1430,10 @@ ngx_http_process_request(ngx_http_reques ngx_log_error(NGX_LOG_INFO, c->log, 0, "client SSL certificate verify error: (%l:%s)", rc, X509_verify_cert_error_string(rc)); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, + (SSL_get0_session(c->ssl->connection))); + ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); return; } @@ -1439,6 +1443,10 @@ ngx_http_process_request(ngx_http_reques { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, + (SSL_get0_session(c->ssl->connection))); + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); return; } @@ -2448,7 +2456,12 @@ ngx_http_post_action(ngx_http_request_t r->read_event_handler = ngx_http_block_reading; - ngx_http_internal_redirect(r, &clcf->post_action, NULL); + if (clcf->post_action.data[0] == '/') { + ngx_http_internal_redirect(r, &clcf->post_action, NULL); + + } else { + ngx_http_named_location(r, &clcf->post_action); + } return NGX_OK; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -221,6 +221,14 @@ ngx_http_script_compile(ngx_http_script_ sc->args = 1; sc->compile_args = 0; + code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) ngx_http_script_mark_args_code; + code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main); if (code == NULL) { @@ -504,7 +512,7 @@ ngx_http_script_copy_capture_len_code(ng e->ip += sizeof(ngx_http_script_copy_capture_code_t); if (code->n < e->ncaptures) { - if ((e->args || e->quote) + if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) { return e->captures[code->n + 1] - e->captures[code->n] @@ -531,7 +539,7 @@ ngx_http_script_copy_capture_code(ngx_ht e->ip += sizeof(ngx_http_script_copy_capture_code_t); if (code->n < e->ncaptures) { - if ((e->args || e->quote) + if ((e->is_args || e->quote) && (e->request->quoted_uri || e->request->plus_in_uri)) { e->pos = (u_char *) ngx_escape_uri(e->pos, @@ -550,6 +558,16 @@ ngx_http_script_copy_capture_code(ngx_ht } +size_t +ngx_http_script_mark_args_code(ngx_http_script_engine_t *e) +{ + e->is_args = 1; + e->ip += sizeof(uintptr_t); + + return 1; +} + + void ngx_http_script_start_args_code(ngx_http_script_engine_t *e) { @@ -700,7 +718,7 @@ ngx_http_script_regex_start_code(ngx_htt le.ncaptures = e->ncaptures; le.quote = code->redirect; - len = 1; /* reserve 1 byte for possible "?" */ + len = 0; while (*(uintptr_t *) le.ip) { lcode = *(ngx_http_script_len_code_pt *) le.ip; @@ -708,6 +726,7 @@ ngx_http_script_regex_start_code(ngx_htt } e->buf.len = len; + e->is_args = le.is_args; } if (code->add_args && r->args.len) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -27,6 +27,7 @@ typedef struct { unsigned flushed:1; unsigned skip:1; unsigned quote:1; + unsigned is_args:1; unsigned log:1; int *captures; @@ -194,6 +195,7 @@ size_t ngx_http_script_copy_var_len_code void ngx_http_script_copy_var_code(ngx_http_script_engine_t *e); size_t ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e); void ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e); +size_t ngx_http_script_mark_args_code(ngx_http_script_engine_t *e); void ngx_http_script_start_args_code(ngx_http_script_engine_t *e); #if (NGX_PCRE) void ngx_http_script_regex_start_code(ngx_http_script_engine_t *e); diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -439,9 +439,6 @@ ngx_http_send_error_page(ngx_http_reques r->err_status = err_page->overwrite; - r->method = NGX_HTTP_GET; - r->method_name = ngx_http_get_name; - r->zero_in_uri = 0; args = NULL; @@ -494,6 +491,10 @@ ngx_http_send_error_page(ngx_http_reques } if (uri->data[0] == '/') { + + r->method = NGX_HTTP_GET; + r->method_name = ngx_http_get_name; + return ngx_http_internal_redirect(r, uri, args); } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -392,6 +392,8 @@ ngx_http_upstream_init(ngx_http_request_ uscf = uscfp[i]; if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->default_port) + || uscf->port == u->resolved->port) && ngx_memcmp(uscf->host.data, host->data, host->len) == 0) { goto found; @@ -420,13 +422,13 @@ ngx_http_upstream_init(ngx_http_request_ ctx->data = r; ctx->timeout = clcf->resolver_timeout; - u->resolved->ctx = ctx; - if (ngx_resolve_name(ctx) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } + u->resolved->ctx = ctx; + return; } @@ -1936,6 +1938,7 @@ ngx_http_upstream_non_buffered_filter(vo cl->buf->pos = b->last; b->last += bytes; cl->buf->last = b->last; + cl->buf->tag = u->output.tag; if (u->length == NGX_MAX_SIZE_T_VALUE) { return NGX_OK; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -201,6 +201,7 @@ typedef struct { typedef struct { ngx_str_t host; in_port_t port; + ngx_uint_t default_port; /* unsigned default_port:1 */ ngx_uint_t naddrs; in_addr_t *addrs; ngx_resolver_ctx_t *ctx; diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -81,6 +81,7 @@ typedef struct { ngx_mail_protocol_t *protocol; ngx_msec_t timeout; + ngx_msec_t resolver_timeout; ngx_flag_t so_keepalive; @@ -89,6 +90,8 @@ typedef struct { u_char *file_name; ngx_int_t line; + ngx_resolver_t *resolver; + /* server ctx */ ngx_mail_conf_ctx_t *ctx; } ngx_mail_core_srv_conf_t; @@ -147,6 +150,8 @@ typedef struct { void **main_conf; void **srv_conf; + ngx_resolver_ctx_t *resolver_ctx; + ngx_mail_proxy_ctx_t *proxy; ngx_uint_t mail_state; @@ -171,6 +176,7 @@ typedef struct { ngx_str_t text; ngx_str_t *addr_text; + ngx_str_t host; ngx_str_t smtp_helo; ngx_uint_t command; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -20,6 +20,8 @@ static char *ngx_mail_core_listen(ngx_co void *conf); static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_command_t ngx_mail_core_commands[] = { @@ -66,6 +68,20 @@ static ngx_command_t ngx_mail_core_comm offsetof(ngx_mail_core_srv_conf_t, server_name), NULL }, + { ngx_string("resolver"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_mail_core_resolver, + NGX_MAIL_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("resolver_timeout"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_core_srv_conf_t, resolver_timeout), + NULL }, + ngx_null_command }; @@ -141,8 +157,14 @@ ngx_mail_core_create_srv_conf(ngx_conf_t */ cscf->timeout = NGX_CONF_UNSET_MSEC; + cscf->resolver_timeout = NGX_CONF_UNSET_MSEC; cscf->so_keepalive = NGX_CONF_UNSET; + cscf->resolver = NGX_CONF_UNSET_PTR; + + cscf->file_name = cf->conf_file->file.name.data; + cscf->line = cf->conf_file->line; + return cscf; } @@ -154,6 +176,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t ngx_mail_core_srv_conf_t *conf = child; ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout, + 30000); ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0); @@ -184,6 +208,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t return NGX_CONF_ERROR; } + ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL); + return NGX_CONF_OK; } @@ -237,9 +263,6 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index]; cscf->ctx = ctx; - cscf->file_name = cf->conf_file->file.name.data; - cscf->line = cf->conf_file->line; - cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index]; cscfp = ngx_array_push(&cmcf->servers); @@ -389,6 +412,44 @@ ngx_mail_core_protocol(ngx_conf_t *cf, n } +static char * +ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_core_srv_conf_t *cscf = conf; + + ngx_url_t u; + ngx_str_t *value; + + value = cf->args->elts; + + if (cscf->resolver != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + cscf->resolver = NULL; + return NGX_CONF_OK; + } + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.host = value[1]; + u.port = 53; + + if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%V: %s", &u.host, u.err); + return NGX_CONF_ERROR; + } + + cscf->resolver = ngx_resolver_create(cf, &u.addrs[0]); + if (cscf->resolver == NULL) { + return NGX_CONF_OK; + } + + return NGX_CONF_OK; +} + + char * ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -528,10 +528,10 @@ ngx_mail_proxy_smtp_handler(ngx_event_t s->connection->log->action = "sending XCLIENT to upstream"; - line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= " - "NAME=[UNAVAILABLE]" CRLF) - 1 + line.len = sizeof("XCLIENT PROTO=SMTP HELO= ADDR= LOGIN= NAME=" + CRLF) - 1 + s->esmtp + s->smtp_helo.len - + s->connection->addr_text.len + s->login.len; + + s->connection->addr_text.len + s->login.len + s->host.len; line.data = ngx_palloc(c->pool, line.len); if (line.data == NULL) { @@ -542,15 +542,14 @@ ngx_mail_proxy_smtp_handler(ngx_event_t if (s->smtp_helo.len) { line.len = ngx_sprintf(line.data, "XCLIENT PROTO=%sSMTP HELO=%V ADDR=%V LOGIN=%V " - "NAME=[UNAVAILABLE]" CRLF, + "NAME=%V" CRLF, (s->esmtp ? "E" : ""), &s->smtp_helo, - &s->connection->addr_text, &s->login) + &s->connection->addr_text, &s->login, &s->host) - line.data; } else { line.len = ngx_sprintf(line.data, - "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V " - "NAME=[UNAVAILABLE]" CRLF, - &s->connection->addr_text, &s->login) + "XCLIENT PROTO=SMTP ADDR=%V LOGIN=%V NAME=%V" CRLF, + &s->connection->addr_text, &s->login, &s->host) - line.data; } diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -11,6 +11,9 @@ #include +static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx); +static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c); static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev); static ngx_int_t ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c); @@ -40,13 +43,182 @@ static u_char smtp_invalid_argument[] = static u_char smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF; +static ngx_str_t smtp_unavailable = ngx_string("[UNAVAILABLE]"); +static ngx_str_t smtp_tempunavail = ngx_string("[TEMPUNAVAIL]"); + + void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c) { + struct sockaddr_in *sin; + ngx_resolver_ctx_t *ctx; + ngx_mail_core_srv_conf_t *cscf; + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + if (cscf->resolver == NULL) { + s->host = smtp_unavailable; + ngx_mail_smtp_greeting(s, c); + return; + } + + c->log->action = "in resolving client address"; + + ctx = ngx_resolve_start(cscf->resolver, NULL); + if (ctx == NULL) { + ngx_mail_close_connection(c); + return; + } + + /* AF_INET only */ + + sin = (struct sockaddr_in *) c->sockaddr; + + ctx->addr = sin->sin_addr.s_addr; + ctx->handler = ngx_mail_smtp_resolve_addr_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + if (ngx_resolve_addr(ctx) != NGX_OK) { + ngx_mail_close_connection(c); + } +} + + +static void +ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx) +{ + ngx_connection_t *c; + ngx_mail_session_t *s; + ngx_mail_core_srv_conf_t *cscf; + + s = ctx->data; + c = s->connection; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%V could not be resolved (%i: %s)", + &c->addr_text, ctx->state, + ngx_resolver_strerror(ctx->state)); + + if (ctx->state == NGX_RESOLVE_NXDOMAIN) { + s->host = smtp_unavailable; + + } else { + s->host = smtp_tempunavail; + } + + ngx_resolve_addr_done(ctx); + + ngx_mail_smtp_greeting(s, s->connection); + + return; + } + + c->log->action = "in resolving client hostname"; + + s->host.data = ngx_pstrdup(c->pool, &ctx->name); + if (s->host.data == NULL) { + ngx_resolve_addr_done(ctx); + ngx_mail_close_connection(c); + return; + } + + s->host.len = ctx->name.len; + + ngx_resolve_addr_done(ctx); + + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "address resolved: %V", &s->host); + + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + ctx = ngx_resolve_start(cscf->resolver, NULL); + if (ctx == NULL) { + ngx_mail_close_connection(c); + return; + } + + ctx->name = s->host; + ctx->type = NGX_RESOLVE_A; + ctx->handler = ngx_mail_smtp_resolve_name_handler; + ctx->data = s; + ctx->timeout = cscf->resolver_timeout; + + if (ngx_resolve_name(ctx) != NGX_OK) { + ngx_mail_close_connection(c); + } +} + + +static void +ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx) +{ + in_addr_t addr; + ngx_uint_t i; + ngx_connection_t *c; + struct sockaddr_in *sin; + ngx_mail_session_t *s; + + s = ctx->data; + c = s->connection; + + if (ctx->state) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "%V could not be resolved (%i: %s)", + &ctx->name, ctx->state, + ngx_resolver_strerror(ctx->state)); + + if (ctx->state == NGX_RESOLVE_NXDOMAIN) { + s->host = smtp_unavailable; + + } else { + s->host = smtp_tempunavail; + } + + } else { + + /* AF_INET only */ + + sin = (struct sockaddr_in *) c->sockaddr; + + for (i = 0; i < ctx->naddrs; i++) { + + addr = ctx->addrs[i]; + + ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0, + "name was resolved to %ud.%ud.%ud.%ud", + (ntohl(addr) >> 24) & 0xff, + (ntohl(addr) >> 16) & 0xff, + (ntohl(addr) >> 8) & 0xff, + ntohl(addr) & 0xff); + + if (addr == sin->sin_addr.s_addr) { + goto found; + } + } + + s->host = smtp_unavailable; + } + +found: + + ngx_resolve_name_done(ctx); + + ngx_mail_smtp_greeting(s, c); +} + + +static void +ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c) +{ ngx_msec_t timeout; ngx_mail_core_srv_conf_t *cscf; ngx_mail_smtp_srv_conf_t *sscf; + ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, + "smtp greeting for \"%V\"", &s->host); + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module); diff --git a/src/os/unix/ngx_channel.c b/src/os/unix/ngx_channel.c --- a/src/os/unix/ngx_channel.c +++ b/src/os/unix/ngx_channel.c @@ -33,7 +33,7 @@ ngx_write_channel(ngx_socket_t s, ngx_ch msg.msg_control = (caddr_t) &cmsg; msg.msg_controllen = sizeof(cmsg); - cmsg.cm.cmsg_len = sizeof(cmsg); + cmsg.cm.cmsg_len = CMSG_LEN(sizeof(int)); cmsg.cm.cmsg_level = SOL_SOCKET; cmsg.cm.cmsg_type = SCM_RIGHTS; *(int *) CMSG_DATA(&cmsg.cm) = ch->fd; @@ -138,7 +138,7 @@ ngx_read_channel(ngx_socket_t s, ngx_cha if (ch->command == NGX_CMD_OPEN_CHANNEL) { - if (cmsg.cm.cmsg_len < (socklen_t) sizeof(cmsg)) { + if (cmsg.cm.cmsg_len < (socklen_t) CMSG_LEN(sizeof(int))) { ngx_log_error(NGX_LOG_ALERT, log, 0, "recvmsg() returned too small ancillary data"); return NGX_ERROR; diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -48,11 +48,16 @@ #if __FreeBSD_version < 400017 -/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */ +/* + * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA() + */ #undef CMSG_SPACE #define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) +#undef CMSG_LEN +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + #undef CMSG_DATA #define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr))) diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -11,7 +11,7 @@ u_char ngx_linux_kern_ostype[50]; u_char ngx_linux_kern_osrelease[50]; -int ngx_linux_rtsig_max; +int ngx_linux_rtsig_max; static ngx_os_io_t ngx_linux_io = { @@ -32,9 +32,6 @@ static ngx_os_io_t ngx_linux_io = { ngx_int_t ngx_os_specific_init(ngx_log_t *log) { - int name[2]; - size_t len; - ngx_err_t err; struct utsname u; if (uname(&u) == -1) { @@ -48,6 +45,12 @@ ngx_os_specific_init(ngx_log_t *log) (void) ngx_cpystrn(ngx_linux_kern_osrelease, (u_char *) u.release, sizeof(ngx_linux_kern_osrelease)); +#if (NGX_HAVE_RTSIG) + { + int name[2]; + size_t len; + ngx_err_t err; + name[0] = CTL_KERN; name[1] = KERN_RTSIGMAX; len = sizeof(ngx_linux_rtsig_max); @@ -65,6 +68,8 @@ ngx_os_specific_init(ngx_log_t *log) ngx_linux_rtsig_max = 0; } + } +#endif ngx_os_io = ngx_linux_io; @@ -78,6 +83,8 @@ ngx_os_specific_status(ngx_log_t *log) ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", ngx_linux_kern_ostype, ngx_linux_kern_osrelease); +#if (NGX_HAVE_RTSIG) ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d", ngx_linux_rtsig_max); +#endif } diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -110,11 +110,16 @@ #include /* ALIGN() */ -/* FreeBSD 3.x has no CMSG_SPACE() at all and has the broken CMSG_DATA() */ +/* + * FreeBSD 3.x has no CMSG_SPACE() and CMSG_LEN() and has the broken CMSG_DATA() + */ #undef CMSG_SPACE #define CMSG_SPACE(l) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(l)) +#undef CMSG_LEN +#define CMSG_LEN(l) (ALIGN(sizeof(struct cmsghdr)) + (l)) + #undef CMSG_DATA #define CMSG_DATA(cmsg) ((u_char *)(cmsg) + ALIGN(sizeof(struct cmsghdr))) diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -994,18 +994,18 @@ ngx_worker_process_exit(ngx_cycle_t *cyc } } - if (ngx_quit) { + if (ngx_exiting) { c = cycle->connections; for (i = 0; i < cycle->connection_n; i++) { if (c[i].fd != -1 && c[i].read && !c[i].read->accept - && !c[i].read->channel) + && !c[i].read->channel + && !c[i].read->resolver) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in %ui connection, " - "aborting", - c[i].fd, i); + "open socket #%d left in %ui connection %s", + c[i].fd, i, ngx_debug_quit ? ", aborting" : ""); ngx_debug_point(); } } @@ -1059,6 +1059,11 @@ ngx_channel_handler(ngx_event_t *ev) ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n); if (n == NGX_ERROR) { + + if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + ngx_del_conn(c, 0); + } + ngx_close_connection(c); return; }