# HG changeset patch # User Igor Sysoev # Date 1187121600 -14400 # Node ID 9fc4ab6673f96b0d3eaefd820b6c2520dd8f103d # Parent f395c7a4c8a8acf53986d19f585b9dedcce66566 nginx 0.6.7 *) Change: now the paths specified in the "include", "auth_basic_user_file", "perl_modules", "ssl_certificate", "ssl_certificate_key", and "ssl_client_certificate" directives are relative to directory of nginx configuration file nginx.conf, but not to nginx prefix directory. *) Change: the --sysconfdir=PATH option in configure was canceled. *) Change: the special make target "upgrade1" was defined for online upgrade of 0.1.x versions. *) Feature: the "server_name" and "valid_referers" directives support regular expressions. *) Feature: the "server" directive in the "upstream" context supports the "backup" parameter. *) Feature: the ngx_http_perl_module supports the $r->discard_request_body. *) Feature: the "add_header Last-Modified ..." directive changes the "Last-Modified" response header line. *) Bugfix: if an response different than 200 was returned to an request with body and connection went to the keep-alive state after the request, then nginx returned 400 for the next request. *) Bugfix: a segmentation fault occurred in worker process if invalid address was set in the "auth_http" directive. *) Bugfix: now nginx uses default listen backlog value 511 on all platforms except FreeBSD. Thanks to Jiang Hong. *) Bugfix: a worker process may got caught in an endless loop, if an "server" inside "upstream" block was marked as "down"; bug appeared in 0.6.6. *) Bugfix: now Solaris sendfilev() is not used to transfer the client request body to FastCGI-server via the unix domain socket. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,48 @@ +Changes with nginx 0.6.7 15 Aug 2007 + + *) Change: now the paths specified in the "include", + "auth_basic_user_file", "perl_modules", "ssl_certificate", + "ssl_certificate_key", and "ssl_client_certificate" directives are + relative to directory of nginx configuration file nginx.conf, but no + to nginx prefix directory. + + *) Change: the --sysconfdir=PATH option in configure was canceled. + + *) Change: the special make target "upgrade1" was defined for online + upgrade of 0.1.x versions. + + *) Feature: the "server_name" and "valid_referers" directives support + regular expressions. + + *) Feature: the "server" directive in the "upstream" context supports + the "backup" parameter. + + *) Feature: the ngx_http_perl_module supports the + $r->discard_request_body. + + *) Feature: the "add_header Last-Modified ..." directive changes the + "Last-Modified" response header line. + + *) Bugfix: if an response different than 200 was returned to an request + with body and connection went to the keep-alive state after the + request, then nginx returned 400 for the next request. + + *) Bugfix: a segmentation fault occurred in worker process if invalid + address was set in the "auth_http" directive. + + *) Bugfix: now nginx uses default listen backlog value 511 on all + platforms except FreeBSD. + Thanks to Jiang Hong. + + *) Bugfix: a worker process may got caught in an endless loop, if an + "server" inside "upstream" block was marked as "down"; bug appeared + in 0.6.6. + + *) Bugfix: now Solaris sendfilev() is not used to transfer the client + request body to FastCGI-server via the unix domain socket. + + Changes with nginx 0.6.6 30 Jul 2007 *) Feature: the --sysconfdir=PATH option in configure. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,48 @@ +Изменения в nginx 0.6.7 15.08.2007 + + *) Изменение: теперь пути, указанные в директивах include, + auth_basic_user_file, perl_modules, ssl_certificate, + ssl_certificate_key и ssl_client_certificate, определяются + относительно каталогу конфигурационного файла nginx.conf, а не + относительно префиксу. + + *) Изменение: параметр --sysconfdir=PATH в configure упразднён. + + *) Изменение: для обновления на лету версий 0.1.x создан специальный + сценарий make upgrade1. + + *) Добавление: директивы server_name и valid_referers поддерживают + регулярные выражения. + + *) Добавление: директива server в блоке upstream поддерживает параметр + backup. + + *) Добавление: модуль ngx_http_perl_module поддерживает метод + $r->discard_request_body. + + *) Добавление: директива "add_header Last-Modified ..." меняет строку + "Last-Modified" в заголовке ответа. + + *) Исправление: если на запрос с телом возвращался ответ с кодом HTTP + отличным от 200, и после этого запроса соединение переходило в + состояние keep-alive, то на следующий запрос nginx возвращал 400. + + *) Исправление: если в директиве auth_http был задан неправильный + адрес, то в рабочем процессе происходил segmentation fault. +
+ + *) Исправление: теперь по умолчанию nginx использует значение 511 для + listen backlog на всех платформах, кроме FreeBSD. + Спасибо Jiang Hong. + + *) Исправление: рабочий процесс мог зациклиться, если server в блоке + upstream был помечен как down; ошибка появилась в 0.6.6. + + *) Исправление: sendfilev() в Solaris теперь не используется при + передаче тела запроса FastCGI-серверу через unix domain сокет. + + Изменения в nginx 0.6.6 30.07.2007 *) Добавление: параметр --sysconfdir=PATH в configure. diff --git a/auto/cc/sunc b/auto/cc/sunc --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -155,3 +155,6 @@ fi # stop on warning CFLAGS="$CFLAGS -errwarn=%all" + +# debug +CFLAGS="$CFLAGS -g" diff --git a/auto/init b/auto/init --- a/auto/init +++ b/auto/init @@ -55,15 +55,24 @@ clean: upgrade: $NGX_SBIN_PATH -t - # upgrade compatibility from 0.1.x to 0.2.x + kill -USR2 \`cat $NGX_PID_PATH\` + sleep 1 + test -f $NGX_PID_PATH.oldbin + + kill -QUIT \`cat $NGX_PID_PATH.oldbin\` + +upgrade1: + # upgrade 0.1.x to 0.2+ + + $NGX_SBIN_PATH -t + cp $NGX_PID_PATH $NGX_PID_PATH.oldbin kill -USR2 \`cat $NGX_PID_PATH\` sleep 1 test -f $NGX_PID_PATH.oldbin - # upgrade compatibility from 0.1.x to 0.2.x cp $NGX_PID_PATH $NGX_PID_PATH.newbin - kill -WINCH \`cat $NGX_PID_PATH.oldbin\` + kill -QUIT \`cat $NGX_PID_PATH.oldbin\` END diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -34,11 +34,11 @@ install: $NGX_OBJS${ngx_dirsep}nginx${ng test -f '$NGX_CONF_PREFIX/mime.types' \ || cp conf/mime.types '$NGX_CONF_PREFIX' - cp conf/mime.types '$NGX_CONF_PATH/mime.types.default' + cp conf/mime.types '$NGX_CONF_PREFIX/mime.types.default' test -f '$NGX_CONF_PREFIX/fastcgi_params' \ || cp conf/fastcgi_params '$NGX_CONF_PREFIX' - cp conf/fastcgi_params '$NGX_CONF_PATH/fastcgi_params.default' + cp conf/fastcgi_params '$NGX_CONF_PREFIX/fastcgi_params.default' test -f '$NGX_CONF_PATH' || cp conf/nginx.conf '$NGX_CONF_PREFIX' cp conf/nginx.conf '$NGX_CONF_PREFIX/nginx.conf.default' diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -124,7 +124,6 @@ do --prefix=*) NGX_PREFIX="$value" ;; --sbin-path=*) NGX_SBIN_PATH="$value" ;; - --sysconfdir=*) NGX_CONF_PREFIX="$value" ;; --conf-path=*) NGX_CONF_PATH="$value" ;; --error-log-path=*) NGX_ERROR_LOG_PATH="$value";; --pid-path=*) NGX_PID_PATH="$value" ;; @@ -242,7 +241,6 @@ cat << END --prefix=PATH set the installation prefix --sbin-path=PATH set path to the nginx binary file - --sysconfdir=PATH set the configuration prefix --conf-path=PATH set path to the nginx.conf file --error-log-path=PATH set path to the error log --pid-path=PATH set path to nginx.pid file @@ -363,7 +361,6 @@ fi NGX_PREFIX=${NGX_PREFIX:-/usr/local/nginx} -NGX_CONF_PREFIX=${NGX_CONF_PREFIX:-$NGX_PREFIX} case ".$NGX_SBIN_PATH" in @@ -385,15 +382,18 @@ case ".$NGX_CONF_PATH" in ;; .) - NGX_CONF_PATH=$NGX_CONF_PREFIX/conf/nginx.conf + NGX_CONF_PATH=$NGX_PREFIX/conf/nginx.conf ;; *) - NGX_CONF_PATH=$NGX_CONF_PREFIX/$NGX_CONF_PATH + NGX_CONF_PATH=$NGX_PREFIX/$NGX_CONF_PATH ;; esac +NGX_CONF_PREFIX=`dirname $NGX_CONF_PATH` + + case ".$NGX_PID_PATH" in ./*) ;; diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -15,7 +15,7 @@ events { http { - include conf/mime.types; + include mime.types; default_type application/octet-stream; #log_format main '$remote_addr - $remote_user [$time_local] $request ' @@ -66,7 +66,7 @@ http { # fastcgi_pass 127.0.0.1:9000; # fastcgi_index index.php; # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; - # include conf/fastcgi_params; + # include fastcgi_params; #} # deny access to .htaccess files, if Apache's document root 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.6" +#define NGINX_VERSION "0.6.7" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" 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 @@ -123,7 +123,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *c ntohs(sin->sin_port)) - ls[i].addr_text.data; - ls[i].backlog = -1; + ls[i].backlog = NGX_LISTEN_BACKLOG; olen = sizeof(int); diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -214,7 +214,13 @@ ngx_ptocidr(ngx_str_t *text, void *cidr) in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - m)))); - return NGX_OK; + if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) { + return NGX_OK; + } + + in_cidr->addr &= in_cidr->mask; + + return NGX_DONE; } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -1038,8 +1038,9 @@ ngx_event_debug_connection(ngx_conf_t *c #if (NGX_DEBUG) ngx_event_conf_t *ecf = conf; + ngx_int_t rc; + ngx_str_t *value; ngx_event_debug_t *dc; - ngx_str_t *value; struct hostent *h; ngx_inet_cidr_t in_cidr; @@ -1056,13 +1057,21 @@ ngx_event_debug_connection(ngx_conf_t *c if (dc->addr != INADDR_NONE) { dc->mask = 0xffffffff; - return NGX_OK; + return NGX_CONF_OK; } - if (ngx_ptocidr(&value[1], &in_cidr) == NGX_OK) { + rc = ngx_ptocidr(&value[1], &in_cidr); + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + rc = NGX_OK; + } + + if (rc == NGX_OK) { dc->mask = in_cidr.mask; dc->addr = in_cidr.addr; - return NGX_OK; + return NGX_CONF_OK; } h = gethostbyname((char *) value[1].data); @@ -1084,7 +1093,7 @@ ngx_event_debug_connection(ngx_conf_t *c #endif - return NGX_OK; + return NGX_CONF_OK; } diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -85,6 +85,8 @@ ngx_event_connect_peer(ngx_peer_connecti c->recv_chain = ngx_recv_chain; c->send_chain = ngx_send_chain; + c->sendfile = 1; + c->log_error = pc->log_error; if (pc->sockaddr->sa_family != AF_INET) { diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -137,6 +137,7 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx { ngx_http_access_loc_conf_t *alcf = conf; + ngx_int_t rc; ngx_str_t *value; ngx_inet_cidr_t in_cidr; ngx_http_access_rule_t *rule; @@ -173,12 +174,19 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx return NGX_CONF_OK; } - if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) { + rc = ngx_ptocidr(&value[1], &in_cidr); + + if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[1]); return NGX_CONF_ERROR; } + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } + rule->mask = in_cidr.mask; rule->addr = in_cidr.addr; 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 @@ -353,9 +353,9 @@ ngx_http_dav_delete_handler(ngx_http_req return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } @@ -469,9 +469,9 @@ ngx_http_dav_mkcol_handler(ngx_http_requ return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } @@ -611,9 +611,9 @@ destination_done: overwrite_done: - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -116,9 +116,9 @@ ngx_http_empty_gif_handler(ngx_http_requ return NGX_HTTP_NOT_ALLOWED; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -89,9 +89,9 @@ ngx_http_flv_handler(ngx_http_request_t return NGX_DECLINED; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -212,12 +212,20 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command cidrin.mask = 0; } else { - if (ngx_ptocidr(&value[0], &cidrin) == NGX_ERROR) { + rc = ngx_ptocidr(&value[0], &cidrin); + + if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[0]); return NGX_CONF_ERROR; } + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", + &value[0]); + } + cidrin.addr = ntohl(cidrin.addr); cidrin.mask = ntohl(cidrin.mask); } diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -9,17 +9,31 @@ #include -typedef struct { - ngx_table_elt_t value; - ngx_array_t *lengths; - ngx_array_t *values; -} ngx_http_header_val_t; +typedef struct ngx_http_header_val_s ngx_http_header_val_t; + +typedef ngx_int_t (*ngx_http_set_header_pt)(ngx_http_request_t *r, + ngx_http_header_val_t *hv, ngx_str_t *value); typedef struct { - time_t expires; - ngx_str_t cache_control; - ngx_array_t *headers; + ngx_str_t name; + ngx_uint_t offset; + ngx_http_set_header_pt handler; +} ngx_http_set_header_t; + + +struct ngx_http_header_val_s { + ngx_table_elt_t value; + ngx_uint_t offset; + ngx_http_set_header_pt handler; + ngx_array_t *lengths; + ngx_array_t *values; +}; + + +typedef struct { + time_t expires; + ngx_array_t *headers; } ngx_http_headers_conf_t; @@ -29,6 +43,13 @@ typedef struct { #define NGX_HTTP_EXPIRES_MAX -2147483644 +static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, + ngx_http_headers_conf_t *conf); +static ngx_int_t ngx_http_add_cache_control(ngx_http_request_t *r, + ngx_http_header_val_t *hv, ngx_str_t *value); +static ngx_int_t ngx_http_set_last_modified(ngx_http_request_t *r, + ngx_http_header_val_t *hv, ngx_str_t *value); + static void *ngx_http_headers_create_conf(ngx_conf_t *cf); static char *ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -39,6 +60,18 @@ static char *ngx_http_headers_add(ngx_co void *conf); +static ngx_http_set_header_t ngx_http_set_headers[] = { + + { ngx_string("Cache-Control"), 0, ngx_http_add_cache_control }, + + { ngx_string("Last-Modified"), + offsetof(ngx_http_headers_out_t, last_modified), + ngx_http_set_last_modified }, + + { ngx_null_string, 0, NULL } +}; + + static ngx_command_t ngx_http_headers_filter_commands[] = { { ngx_string("expires"), @@ -98,13 +131,15 @@ static ngx_http_output_header_filter_pt static ngx_int_t ngx_http_headers_filter(ngx_http_request_t *r) { - size_t len; + ngx_str_t value; ngx_uint_t i; - ngx_table_elt_t *expires, *cc, **ccp, *out; ngx_http_header_val_t *h; ngx_http_headers_conf_t *conf; - if (r != r->main + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); + + if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL) + || r != r->main || (r->headers_out.status != NGX_HTTP_OK && r->headers_out.status != NGX_HTTP_NO_CONTENT && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY @@ -114,124 +149,73 @@ ngx_http_headers_filter(ngx_http_request return ngx_http_next_header_filter(r); } - conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); - if (conf->expires != NGX_HTTP_EXPIRES_OFF) { - - expires = r->headers_out.expires; - - if (expires == NULL) { + if (ngx_http_set_expires(r, conf) != NGX_OK) { + return NGX_ERROR; + } + } - expires = ngx_list_push(&r->headers_out.headers); - if (expires == NULL) { - return NGX_ERROR; - } - - r->headers_out.expires = expires; - - expires->hash = 1; - expires->key.len = sizeof("Expires") - 1; - expires->key.data = (u_char *) "Expires"; - } + if (conf->headers) { + h = conf->headers->elts; + for (i = 0; i < conf->headers->nelts; i++) { - len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); - expires->value.len = len - 1; - - ccp = r->headers_out.cache_control.elts; - - if (ccp == NULL) { + if (h[i].lengths == NULL) { + value = h[i].value.value; - if (ngx_array_init(&r->headers_out.cache_control, r->pool, - 1, sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - return NGX_ERROR; - } - - ccp = ngx_array_push(&r->headers_out.cache_control); - if (ccp == NULL) { - return NGX_ERROR; - } - - cc = ngx_list_push(&r->headers_out.headers); - if (cc == NULL) { - return NGX_ERROR; + } else { + if (ngx_http_script_run(r, &value, h[i].lengths->elts, 0, + h[i].values->elts) + == NULL) + { + return NGX_ERROR; + } } - cc->hash = 1; - cc->key.len = sizeof("Cache-Control") - 1; - cc->key.data = (u_char *) "Cache-Control"; - - *ccp = cc; - - } else { - for (i = 1; i < r->headers_out.cache_control.nelts; i++) { - ccp[i]->hash = 0; - } - - cc = ccp[0]; - } - - if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { - expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; - - cc->value.len = sizeof("no-cache") - 1; - cc->value.data = (u_char *) "no-cache"; - - } else if (conf->expires == NGX_HTTP_EXPIRES_MAX) { - expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT"; - - /* 10 years */ - cc->value.len = sizeof("max-age=315360000") - 1; - cc->value.data = (u_char *) "max-age=315360000"; - - } else { - expires->value.data = ngx_palloc(r->pool, len); - if (expires->value.data == NULL) { + if (h[i].handler(r, &h[i], &value) != NGX_OK) { return NGX_ERROR; } - - if (conf->expires == 0) { - ngx_memcpy(expires->value.data, ngx_cached_http_time.data, - ngx_cached_http_time.len + 1); - - cc->value.len = sizeof("max-age=0") - 1; - cc->value.data = (u_char *) "max-age=0"; - - } else { - ngx_http_time(expires->value.data, ngx_time() + conf->expires); - - if (conf->expires < 0) { - cc->value.len = sizeof("no-cache") - 1; - cc->value.data = (u_char *) "no-cache"; - - } else { - cc->value.data = ngx_palloc(r->pool, sizeof("max-age=") - + NGX_TIME_T_LEN + 1); - if (cc->value.data == NULL) { - return NGX_ERROR; - } - - cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", - conf->expires) - - cc->value.data; - } - } } } - if (conf->cache_control.len) { + return ngx_http_next_header_filter(r); +} + - ccp = r->headers_out.cache_control.elts; +static ngx_int_t +ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) +{ + size_t len; + ngx_uint_t i; + ngx_table_elt_t *expires, *cc, **ccp; - if (ccp == NULL) { + expires = r->headers_out.expires; + + if (expires == NULL) { + + expires = ngx_list_push(&r->headers_out.headers); + if (expires == NULL) { + return NGX_ERROR; + } - if (ngx_array_init(&r->headers_out.cache_control, r->pool, - 1, sizeof(ngx_table_elt_t *)) - != NGX_OK) - { - return NGX_ERROR; - } + r->headers_out.expires = expires; + + expires->hash = 1; + expires->key.len = sizeof("Expires") - 1; + expires->key.data = (u_char *) "Expires"; + } + + len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); + expires->value.len = len - 1; + + ccp = r->headers_out.cache_control.elts; + + if (ccp == NULL) { + + if (ngx_array_init(&r->headers_out.cache_control, r->pool, + 1, sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; } ccp = ngx_array_push(&r->headers_out.cache_control); @@ -247,37 +231,161 @@ ngx_http_headers_filter(ngx_http_request cc->hash = 1; cc->key.len = sizeof("Cache-Control") - 1; cc->key.data = (u_char *) "Cache-Control"; - cc->value = conf->cache_control; *ccp = cc; + + } else { + for (i = 1; i < r->headers_out.cache_control.nelts; i++) { + ccp[i]->hash = 0; + } + + cc = ccp[0]; + } + + if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { + expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; + + cc->value.len = sizeof("no-cache") - 1; + cc->value.data = (u_char *) "no-cache"; + + return NGX_OK; + } + + if (conf->expires == NGX_HTTP_EXPIRES_MAX) { + expires->value.data = (u_char *) "Thu, 31 Dec 2037 23:55:55 GMT"; + + /* 10 years */ + cc->value.len = sizeof("max-age=315360000") - 1; + cc->value.data = (u_char *) "max-age=315360000"; + + return NGX_OK; + } + + expires->value.data = ngx_palloc(r->pool, len); + if (expires->value.data == NULL) { + return NGX_ERROR; + } + + if (conf->expires == 0) { + ngx_memcpy(expires->value.data, ngx_cached_http_time.data, + ngx_cached_http_time.len + 1); + + cc->value.len = sizeof("max-age=0") - 1; + cc->value.data = (u_char *) "max-age=0"; + + return NGX_OK; } - if (conf->headers) { - h = conf->headers->elts; - for (i = 0; i < conf->headers->nelts; i++) { - out = ngx_list_push(&r->headers_out.headers); - if (out == NULL) { - return NGX_ERROR; - } + ngx_http_time(expires->value.data, ngx_time() + conf->expires); + + if (conf->expires < 0) { + cc->value.len = sizeof("no-cache") - 1; + cc->value.data = (u_char *) "no-cache"; + + return NGX_OK; + } - out->hash = h[i].value.hash; - out->key = h[i].value.key; + cc->value.data = ngx_palloc(r->pool, + sizeof("max-age=") + NGX_TIME_T_LEN + 1); + if (cc->value.data == NULL) { + return NGX_ERROR; + } + + cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", conf->expires) + - cc->value.data; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_add_header(ngx_http_request_t *r, ngx_http_header_val_t *hv, + ngx_str_t *value) +{ + ngx_table_elt_t *h; - if (h[i].lengths == NULL) { - out->value = h[i].value.value; - continue; - } + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->hash = hv->value.hash; + h->key = hv->value.key; + h->value = *value; + + return NGX_OK; +} + - if (ngx_http_script_run(r, &out->value, h[i].lengths->elts, 0, - h[i].values->elts) - == NULL) - { - return NGX_ERROR; - } +static ngx_int_t +ngx_http_add_cache_control(ngx_http_request_t *r, ngx_http_header_val_t *hv, + ngx_str_t *value) +{ + ngx_table_elt_t *cc, **ccp; + + ccp = r->headers_out.cache_control.elts; + + if (ccp == NULL) { + + if (ngx_array_init(&r->headers_out.cache_control, r->pool, + 1, sizeof(ngx_table_elt_t *)) + != NGX_OK) + { + return NGX_ERROR; } } - return ngx_http_next_header_filter(r); + ccp = ngx_array_push(&r->headers_out.cache_control); + if (ccp == NULL) { + return NGX_ERROR; + } + + cc = ngx_list_push(&r->headers_out.headers); + if (cc == NULL) { + return NGX_ERROR; + } + + cc->hash = 1; + cc->key.len = sizeof("Cache-Control") - 1; + cc->key.data = (u_char *) "Cache-Control"; + cc->value = *value; + + *ccp = cc; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv, + ngx_str_t *value) +{ + ngx_table_elt_t *h, **old; + + if (hv->offset) { + old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); + + } else { + old = NULL; + } + + if (old == NULL || *old == NULL) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + } else { + h = *old; + } + + h->hash = hv->value.hash; + h->key = hv->value.key; + h->value = *value; + + r->headers_out.last_modified_time = -1; + + return NGX_OK; } @@ -294,8 +402,6 @@ ngx_http_headers_create_conf(ngx_conf_t /* * set by ngx_pcalloc(): * - * conf->cache_control.len = 0; - * conf->cache_control.data = NULL; * conf->headers = NULL; */ @@ -313,11 +419,7 @@ ngx_http_headers_merge_conf(ngx_conf_t * if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { conf->expires = (prev->expires == NGX_HTTP_EXPIRES_UNSET) ? - NGX_HTTP_EXPIRES_OFF : prev->expires; - } - - if (conf->cache_control.data == NULL) { - conf->cache_control = prev->cache_control; + NGX_HTTP_EXPIRES_OFF : prev->expires; } if (conf->headers == NULL) { @@ -406,16 +508,13 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx ngx_int_t n; ngx_str_t *value; + ngx_uint_t i; ngx_http_header_val_t *h; + ngx_http_set_header_t *sh; ngx_http_script_compile_t sc; value = cf->args->elts; - if (ngx_strcasecmp(value[1].data, (u_char *) "cache-control") == 0) { - hcf->cache_control = value[2]; - return NGX_CONF_OK; - } - if (hcf->headers == NULL) { hcf->headers = ngx_array_create(cf->pool, 1, sizeof(ngx_http_header_val_t)); @@ -432,9 +531,22 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx h->value.hash = 1; h->value.key = value[1]; h->value.value = value[2]; + h->offset = 0; + h->handler = ngx_http_add_header; h->lengths = NULL; h->values = NULL; + sh = ngx_http_set_headers; + for (i = 0; sh[i].name.len; i++) { + if (ngx_strcasecmp(value[1].data, sh[i].name.data) != 0) { + continue; + } + + h->offset = sh[i].offset; + h->handler = sh[i].handler; + break; + } + n = ngx_http_script_variables_count(&value[2]); if (n == 0) { 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 @@ -167,9 +167,9 @@ ngx_http_memcached_handler(ngx_http_requ return NGX_HTTP_NOT_ALLOWED; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -188,6 +188,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx { ngx_http_realip_loc_conf_t *rlcf = conf; + ngx_int_t rc; ngx_str_t *value; ngx_inet_cidr_t in_cidr; ngx_http_realip_from_t *from; @@ -215,12 +216,19 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx return NGX_CONF_OK; } - if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) { + rc = ngx_ptocidr(&value[1], &in_cidr); + + if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[1]); return NGX_CONF_ERROR; } + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } + from->mask = in_cidr.mask; from->addr = in_cidr.addr; diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -11,9 +11,27 @@ #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) +#if (NGX_PCRE) + +typedef struct { + ngx_regex_t *regex; + ngx_str_t name; +} ngx_http_referer_regex_t; + +#else + +#define ngx_regex_t void + +#endif + + typedef struct { ngx_hash_combined_t hash; +#if (NGX_PCRE) + ngx_array_t *regex; +#endif + ngx_flag_t no_referer; ngx_flag_t blocked_referer; @@ -28,6 +46,8 @@ static char *ngx_http_valid_referers(ngx void *conf); static char *ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, ngx_str_t *value, ngx_str_t *uri); +static char *ngx_http_add_regex_referer(ngx_conf_t *cf, + ngx_http_referer_conf_t *rlcf, ngx_str_t *name, ngx_regex_t *regex); static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, const void *two); @@ -80,18 +100,27 @@ static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - u_char *p, *ref, *last; - size_t len; - ngx_str_t *uri; - ngx_uint_t i, key; - ngx_http_referer_conf_t *rlcf; - u_char buf[256]; + u_char *p, *ref, *last; + size_t len; + ngx_str_t *uri; + ngx_uint_t i, key; + ngx_http_referer_conf_t *rlcf; + u_char buf[256]; +#if (NGX_PCRE) + ngx_int_t n; + ngx_str_t referer; + ngx_http_referer_regex_t *regex; +#endif rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); if (rlcf->hash.hash.buckets == NULL && rlcf->hash.wc_head == NULL - && rlcf->hash.wc_tail == NULL) + && rlcf->hash.wc_tail == NULL +#if (NGX_PCRE) + && rlcf->regex == NULL +#endif + ) { goto valid; } @@ -135,14 +164,44 @@ ngx_http_referer_variable(ngx_http_reque } } - len = p - ref; - - uri = ngx_hash_find_combined(&rlcf->hash, key, buf, len); + uri = ngx_hash_find_combined(&rlcf->hash, key, buf, p - ref); if (uri) { goto uri; } +#if (NGX_PCRE) + + if (rlcf->regex) { + + referer.len = len - 7; + referer.data = ref; + + regex = rlcf->regex->elts; + + for (i = 0; i < rlcf->regex->nelts; i++) { + n = ngx_regex_exec(regex[i].regex, &referer, NULL, 0); + + if (n == NGX_REGEX_NO_MATCHED) { + continue; + } + + if (n < 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n + " failed: %d on \"%V\" using \"%V\"", + n, &referer, ®ex[i].name); + return NGX_ERROR; + } + + /* match */ + + goto valid; + } + } + +#endif + invalid: *v = ngx_http_variable_true_value; @@ -357,6 +416,21 @@ ngx_http_valid_referers(ngx_conf_t *cf, sn = cscf->server_names.elts; for (n = 0; n < cscf->server_names.nelts; n++) { + +#if (NGX_PCRE) + if (sn[n].regex) { + + if (ngx_http_add_regex_referer(cf, rlcf, &sn[n].name, + sn[n].regex) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + continue; + } +#endif + if (ngx_http_add_referer(cf, rlcf->keys, &sn[n].name, &uri) != NGX_OK) { @@ -367,6 +441,15 @@ ngx_http_valid_referers(ngx_conf_t *cf, continue; } + if (value[i].data[0] == '~') { + if (ngx_http_add_regex_referer(cf, rlcf, &value[i], NULL) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + continue; + } + p = (u_char *) ngx_strchr(value[i].data, '/'); if (p) { @@ -423,6 +506,64 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx } +static char * +ngx_http_add_regex_referer(ngx_conf_t *cf, ngx_http_referer_conf_t *rlcf, + ngx_str_t *name, ngx_regex_t *regex) +{ +#if (NGX_PCRE) + ngx_str_t err; + ngx_http_referer_regex_t *rr; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + if (rlcf->regex == NULL) { + rlcf->regex = ngx_array_create(cf->pool, 2, + sizeof(ngx_http_referer_regex_t)); + if (rlcf->regex == NULL) { + return NGX_CONF_ERROR; + } + } + + rr = ngx_array_push(rlcf->regex); + if (rr == NULL) { + return NGX_CONF_ERROR; + } + + if (regex) { + rr->regex = regex; + rr->name = *name; + + return NGX_CONF_OK; + } + + err.len = NGX_MAX_CONF_ERRSTR; + err.data = errstr; + + name->len--; + name->data++; + + rr->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); + + if (rr->regex == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + return NGX_CONF_ERROR; + } + + rr->name = *name; + + return NGX_CONF_OK; + +#else + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the using of the regex \"%V\" requires PCRE library", + name); + + return NGX_CONF_ERROR; + +#endif +} + + static int ngx_libc_cdecl ngx_http_cmp_referer_wildcards(const void *one, const void *two) { diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -100,9 +100,9 @@ ngx_http_static_handler(ngx_http_request return NGX_DECLINED; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -69,9 +69,9 @@ static ngx_int_t ngx_http_status_handler return NGX_HTTP_NOT_ALLOWED; } - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); - if (rc != NGX_OK && rc != NGX_AGAIN) { + if (rc != NGX_OK) { return rc; } 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.6'; +our $VERSION = '0.6.7'; 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 @@ -425,6 +425,17 @@ request_body_file(r) void +discard_request_body(r) + CODE: + + ngx_http_request_t *r; + + ngx_http_perl_set_request(r); + + ngx_http_discard_request_body(r); + + +void header_out(r, key, value) CODE: @@ -461,8 +472,6 @@ header_out(r, key, value) r->headers_out.content_length = header; } - XSRETURN_EMPTY; - void filename(r) @@ -589,8 +598,6 @@ print(r, ...) (void) ngx_http_perl_output(r, b); - XSRETURN_EMPTY; - void sendfile(r, filename, offset = -1, bytes = 0) @@ -677,8 +684,6 @@ sendfile(r, filename, offset = -1, bytes (void) ngx_http_perl_output(r, b); - XSRETURN_EMPTY; - void flush(r) @@ -744,8 +749,6 @@ allow_ranges(r) r->allow_ranges = 1; - XSRETURN_EMPTY; - void unescape(r, text, type = 0) @@ -942,8 +945,6 @@ sleep(r, sleep, next) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl sleep: %d", ctx->sleep); - XSRETURN_EMPTY; - void log_error(r, err, msg) @@ -974,5 +975,3 @@ log_error(r, err, msg) p = (u_char *) SvPV(msg, len); ngx_log_error(NGX_LOG_ERR, r->connection->log, e, "perl: %s", p); - - XSRETURN_EMPTY; 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 @@ -98,6 +98,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma ngx_http_core_loc_conf_t *clcf; ngx_http_phase_handler_pt checker; ngx_http_core_main_conf_t *cmcf; +#if (NGX_PCRE) + ngx_uint_t regex; +#endif #if (NGX_WIN32) ngx_iocp_conf_t *iocpcf; #endif @@ -655,10 +658,21 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma return NGX_CONF_ERROR; } +#if (NGX_PCRE) + regex = 0; +#endif + name = in_addr[a].names.elts; for (s = 0; s < in_addr[a].names.nelts; s++) { +#if (NGX_PCRE) + if (name[s].regex) { + regex++; + continue; + } +#endif + rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, NGX_HASH_WILDCARD_KEY); @@ -740,6 +754,27 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } ngx_destroy_pool(ha.temp_pool); + +#if (NGX_PCRE) + + if (regex == 0) { + continue; + } + + in_addr[a].nregex = regex; + in_addr[a].regex = ngx_palloc(cf->pool, + regex * sizeof(ngx_http_server_name_t)); + + if (in_addr[a].regex == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) { + if (name[s].regex) { + in_addr[a].regex[i++] = name[s]; + } + } +#endif } in_addr = in_port[p].addrs.elts; @@ -871,9 +906,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } hip->addrs[i].virtual_names = vn; - vn->hash = in_addr[i].hash; - vn->wc_head = in_addr[i].wc_head; - vn->wc_tail = in_addr[i].wc_tail; + vn->names.hash = in_addr[i].hash; + vn->names.wc_head = in_addr[i].wc_head; + vn->names.wc_tail = in_addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = in_addr[i].nregex; + vn->regex = in_addr[i].regex; +#endif } if (done) { @@ -932,7 +971,8 @@ ngx_http_add_address(ngx_conf_t *cf, ngx if (in_port->addrs.elts == NULL) { if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4, - sizeof(ngx_http_conf_in_addr_t)) != NGX_OK) + sizeof(ngx_http_conf_in_addr_t)) + != NGX_OK) { return NGX_ERROR; } @@ -949,6 +989,10 @@ ngx_http_add_address(ngx_conf_t *cf, ngx in_addr->wc_head = NULL; in_addr->wc_tail = NULL; in_addr->names.elts = NULL; +#if (NGX_PCRE) + in_addr->nregex = 0; + in_addr->regex = NULL; +#endif in_addr->core_srv_conf = cscf; in_addr->default_server = lscf->conf.default_server; in_addr->bind = lscf->conf.bind; @@ -981,13 +1025,15 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h if (in_addr->names.elts == NULL) { if (ngx_array_init(&in_addr->names, cf->temp_pool, 4, - sizeof(ngx_http_server_name_t)) != NGX_OK) + sizeof(ngx_http_server_name_t)) + != NGX_OK) { return NGX_ERROR; } } server_names = cscf->server_names.elts; + for (i = 0; i < cscf->server_names.nelts; i++) { for (n = 0; n < server_names[i].name.len; n++) { @@ -998,7 +1044,6 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "name: %V", &server_names[i].name); - name = ngx_array_push(&in_addr->names); if (name == NULL) { return NGX_ERROR; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -98,7 +98,8 @@ size_t ngx_http_get_time(char *buf, time -ngx_int_t ngx_http_discard_body(ngx_http_request_t *r); +ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r); +void ngx_http_block_reading(ngx_http_request_t *r); extern ngx_module_t ngx_http_module; 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 @@ -933,14 +933,19 @@ ngx_http_core_find_location(ngx_http_req ngx_array_t *locations, ngx_uint_t regex_start, size_t len) { ngx_int_t n, rc; - ngx_uint_t i, found, noregex; + ngx_uint_t i, found; ngx_http_core_loc_conf_t *clcf, **clcfp; +#if (NGX_PCRE) + ngx_uint_t noregex; +#endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "find location for \"%V\"", &r->uri); found = 0; +#if (NGX_PCRE) noregex = 0; +#endif clcfp = locations->elts; for (i = 0; i < locations->nelts; i++) { @@ -998,9 +1003,12 @@ ngx_http_core_find_location(ngx_http_req break; } + found = 1; + r->loc_conf = clcfp[i]->loc_conf; +#if (NGX_PCRE) noregex = clcfp[i]->noregex; - found = 1; +#endif } } @@ -2219,7 +2227,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t #endif ls->family = AF_INET; - ls->conf.backlog = -1; + ls->conf.backlog = NGX_LISTEN_BACKLOG; ls->conf.rcvbuf = -1; ls->conf.sndbuf = -1; } @@ -2570,7 +2578,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ls->port = u.port; ls->file_name = cf->conf_file->file.name; ls->line = cf->conf_file->line; - ls->conf.backlog = -1; + ls->conf.backlog = NGX_LISTEN_BACKLOG; ls->conf.rcvbuf = -1; ls->conf.sndbuf = -1; @@ -2692,6 +2700,10 @@ ngx_http_core_server_name(ngx_conf_t *cf ngx_str_t *value, name; ngx_uint_t i; ngx_http_server_name_t *sn; +#if (NGX_PCRE) + ngx_str_t err; + u_char errstr[NGX_MAX_CONF_ERRSTR]; +#endif value = cf->args->elts; @@ -2705,6 +2717,13 @@ ngx_http_core_server_name(ngx_conf_t *cf return NGX_CONF_ERROR; } + if (value[1].data[0] == '~') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "first server name \"%V\" " + "must not be regular expression", &value[1]); + return NGX_CONF_ERROR; + } + name = value[1]; if (ch == '.') { @@ -2748,9 +2767,42 @@ ngx_http_core_server_name(ngx_conf_t *cf return NGX_CONF_ERROR; } +#if (NGX_PCRE) + sn->regex = NULL; +#endif + sn->core_srv_conf = cscf; sn->name.len = value[i].len; sn->name.data = value[i].data; - sn->core_srv_conf = cscf; + + if (value[i].data[0] != '~') { + continue; + } + +#if (NGX_PCRE) + err.len = NGX_MAX_CONF_ERRSTR; + err.data = errstr; + + value[i].len--; + value[i].data++; + + sn->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool, + &err); + + if (sn->regex == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + return NGX_CONF_ERROR; + } + + sn->name.len = value[i].len; + sn->name.data = value[i].data; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the using of the regex \"%V\" " + "requires PCRE library", &value[i]); + + return NGX_CONF_ERROR; +#endif } return NGX_CONF_OK; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -151,8 +151,10 @@ typedef struct { typedef struct { in_addr_t addr; + /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *core_srv_conf; + ngx_http_virtual_names_t *virtual_names; } ngx_http_in_addr_t; @@ -180,6 +182,12 @@ typedef struct { ngx_array_t names; /* array of ngx_http_server_name_t */ +#if (NGX_PCRE) + ngx_uint_t nregex; + ngx_http_server_name_t *regex; + +#endif + /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *core_srv_conf; @@ -190,10 +198,13 @@ typedef struct { } ngx_http_conf_in_addr_t; -typedef struct { +struct ngx_http_server_name_s { +#if (NGX_PCRE) + ngx_regex_t *regex; +#endif + ngx_http_core_srv_conf_t *core_srv_conf; /* virtual name server conf */ ngx_str_t name; - ngx_http_core_srv_conf_t *core_srv_conf; /* virtual name server conf */ -} ngx_http_server_name_t; +}; typedef struct { 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 @@ -33,8 +33,7 @@ static void ngx_http_request_handler(ngx static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); static void ngx_http_writer(ngx_http_request_t *r); -static void ngx_http_block_read(ngx_http_request_t *r); -static void ngx_http_test_read(ngx_http_request_t *r); +static void ngx_http_test_reading(ngx_http_request_t *r); static void ngx_http_set_keepalive(ngx_http_request_t *r); static void ngx_http_keepalive_handler(ngx_event_t *ev); static void ngx_http_set_lingering_close(ngx_http_request_t *r); @@ -1442,7 +1441,7 @@ ngx_http_process_request(ngx_http_reques c->read->handler = ngx_http_request_handler; c->write->handler = ngx_http_request_handler; - r->read_event_handler = ngx_http_block_read; + r->read_event_handler = ngx_http_block_reading; ngx_http_handler(r); @@ -1454,18 +1453,56 @@ static void ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len, ngx_uint_t hash) { - ngx_http_virtual_names_t *vn; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - - vn = r->virtual_names; - - cscf = ngx_hash_find_combined(vn, hash, host, len); +#if (NGX_PCRE) + ngx_int_t n; + ngx_uint_t i; + ngx_str_t name; + ngx_http_server_name_t *sn; +#endif + + cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, host, len); if (cscf) { goto found; } +#if (NGX_PCRE) + + if (r->virtual_names->nregex) { + + name.len = len; + name.data = host; + + sn = r->virtual_names->regex; + + for (i = 0; i < r->virtual_names->nregex; i++) { + + n = ngx_regex_exec(sn[i].regex, &name, NULL, 0); + + if (n == NGX_REGEX_NO_MATCHED) { + continue; + } + + if (n < 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n + " failed: %d on \"%V\" using \"%V\"", + n, &name, &sn[i].name); + return; + } + + /* match */ + + cscf = sn[i].core_srv_conf; + + goto found; + } + } + +#endif + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); if (cscf->wildcard) { @@ -1702,7 +1739,7 @@ ngx_http_set_write_handler(ngx_http_requ r->http_state = NGX_HTTP_WRITING_REQUEST_STATE; - r->read_event_handler = ngx_http_test_read; + r->read_event_handler = ngx_http_test_reading; r->write_event_handler = ngx_http_writer; wev = r->connection->write; @@ -1812,11 +1849,11 @@ ngx_http_writer(ngx_http_request_t *r) } -static void -ngx_http_block_read(ngx_http_request_t *r) +void +ngx_http_block_reading(ngx_http_request_t *r) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http read blocked"); + "http reading blocked"); /* aio does not call this handler */ @@ -1833,7 +1870,7 @@ ngx_http_block_read(ngx_http_request_t * static void -ngx_http_test_read(ngx_http_request_t *r) +ngx_http_test_reading(ngx_http_request_t *r) { int n; char buf[1]; @@ -1844,7 +1881,7 @@ ngx_http_test_read(ngx_http_request_t *r c = r->connection; rev = c->read; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test read"); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test reading"); #if (NGX_HAVE_KQUEUE) @@ -1922,8 +1959,16 @@ ngx_http_set_keepalive(ngx_http_request_ c = r->connection; rev = c->read; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "set http keepalive handler"); + if (r->discard_body) { + r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000); + ngx_add_timer(rev, clcf->lingering_timeout); + return; + } + c->log->action = "closing request"; hc = r->http_connection; @@ -1967,8 +2012,6 @@ ngx_http_set_keepalive(ngx_http_request_ } } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_http_request_done(r, 0); c->data = hc; @@ -2381,7 +2424,7 @@ ngx_http_post_action(ngx_http_request_t r->header_only = 1; r->post_action = 1; - r->read_event_handler = ngx_http_block_read; + r->read_event_handler = ngx_http_block_reading; ngx_http_internal_redirect(r, &clcf->post_action, NULL); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -275,7 +275,15 @@ typedef struct { } ngx_http_connection_t; -typedef ngx_hash_combined_t ngx_http_virtual_names_t; +typedef struct ngx_http_server_name_s ngx_http_server_name_t; + + +typedef struct { + ngx_hash_combined_t names; + + ngx_uint_t nregex; + ngx_http_server_name_t *regex; +} ngx_http_virtual_names_t; typedef void (*ngx_http_cleanup_pt)(void *data); diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -14,8 +14,8 @@ static void ngx_http_read_client_request static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body); -static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r); -static ngx_int_t ngx_http_read_discarded_body(ngx_http_request_t *r); +static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); /* @@ -425,7 +425,7 @@ ngx_http_write_request_body(ngx_http_req ngx_int_t -ngx_http_discard_body(ngx_http_request_t *r) +ngx_http_discard_request_body(ngx_http_request_t *r) { ssize_t size; ngx_event_t *rev; @@ -442,12 +442,12 @@ ngx_http_discard_body(ngx_http_request_t ngx_del_timer(rev); } - r->discard_body = 1; - if (r->headers_in.content_length_n <= 0) { return NGX_OK; } + r->discard_body = 1; + size = r->header_in->last - r->header_in->pos; if (size) { @@ -461,38 +461,87 @@ ngx_http_discard_body(ngx_http_request_t } } - r->read_event_handler = ngx_http_read_discarded_body_handler; + r->read_event_handler = ngx_http_read_discarded_request_body_handler; if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - return ngx_http_read_discarded_body(r); + (void) ngx_http_read_discarded_request_body(r); + + return NGX_OK; } static void -ngx_http_read_discarded_body_handler(ngx_http_request_t *r) +ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r) { - ngx_int_t rc; + ngx_int_t rc; + ngx_msec_t timer; + ngx_event_t *rev; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; + + c = r->connection; + rev = c->read; - rc = ngx_http_read_discarded_body(r); + if (rev->timedout) { + c->timedout = 1; + c->error = 1; + ngx_http_finalize_request(r, 0); + return; + } - if (rc == NGX_AGAIN) { - if (ngx_handle_read_event(r->connection->read, 0) == NGX_ERROR) { - ngx_http_finalize_request(r, rc); + if (r->lingering_time) { + timer = r->lingering_time - ngx_time(); + + if (timer <= 0) { + r->discard_body = 0; + ngx_http_finalize_request(r, 0); return; } + + } else { + timer = 0; + } + + rc = ngx_http_read_discarded_request_body(r); + + if (rc == NGX_OK) { + + r->discard_body = 0; + + if (r->done) { + ngx_http_finalize_request(r, 0); + } + + return; } - if (rc != NGX_OK) { + /* rc == NGX_AGAIN */ + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { ngx_http_finalize_request(r, rc); + return; + } + + if (timer) { + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + timer *= 1000; + + if (timer > clcf->lingering_timeout) { + timer = clcf->lingering_timeout; + } + + ngx_add_timer(rev, timer); } } static ngx_int_t -ngx_http_read_discarded_body(ngx_http_request_t *r) +ngx_http_read_discarded_request_body(ngx_http_request_t *r) { size_t size; ssize_t n; @@ -501,33 +550,30 @@ ngx_http_read_discarded_body(ngx_http_re ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http read discarded body"); - if (r->headers_in.content_length_n == 0) { - return NGX_OK; - } + do { + if (r->headers_in.content_length_n == 0) { + r->read_event_handler = ngx_http_block_reading; + return NGX_OK; + } - size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ? - NGX_HTTP_DISCARD_BUFFER_SIZE: - (size_t) r->headers_in.content_length_n; + size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ? + NGX_HTTP_DISCARD_BUFFER_SIZE: + (size_t) r->headers_in.content_length_n; - n = r->connection->recv(r->connection, buffer, size); - - if (n == NGX_ERROR) { - - r->connection->error = 1; + n = r->connection->recv(r->connection, buffer, size); - /* - * if a client request body is discarded then we already set - * some HTTP response code for client and we can ignore the error - */ - - return NGX_OK; - } + if (n == NGX_ERROR) { + r->connection->error = 1; + return NGX_OK; + } - if (n == NGX_AGAIN) { - return NGX_AGAIN; - } + if (n == NGX_AGAIN) { + return NGX_AGAIN; + } - r->headers_in.content_length_n -= n; + r->headers_in.content_length_n -= n; - return NGX_OK; + } while (r->connection->read->ready); + + return NGX_AGAIN; } 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 @@ -327,7 +327,7 @@ ngx_http_special_response_handler(ngx_ht ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http special response: %d, \"%V\"", error, &r->uri); - rc = ngx_http_discard_body(r); + rc = ngx_http_discard_request_body(r); if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { error = NGX_HTTP_INTERNAL_SERVER_ERROR; 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 @@ -565,9 +565,11 @@ ngx_http_upstream_connect(ngx_http_reque if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams"); + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_NOLIVE); + return; } - if (rc == NGX_BUSY || rc == NGX_DECLINED) { + if (rc == NGX_DECLINED) { ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); return; } @@ -581,7 +583,7 @@ ngx_http_upstream_connect(ngx_http_reque c->write->handler = ngx_http_upstream_send_request_handler; c->read->handler = ngx_http_upstream_process_header; - c->sendfile = r->connection->sendfile; + c->sendfile &= r->connection->sendfile; c->pool = r->pool; c->read->log = c->write->log = c->log = r->connection->log; @@ -2153,7 +2155,9 @@ ngx_http_upstream_next(ngx_http_request_ state = NGX_PEER_FAILED; } - u->peer.free(&u->peer, u->peer.data, state); + if (ft_type != NGX_HTTP_UPSTREAM_FT_NOLIVE) { + u->peer.free(&u->peer, u->peer.data, state); + } if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT, @@ -3118,6 +3122,17 @@ ngx_http_upstream_server(ngx_conf_t *cf, continue; } + if (ngx_strncmp(value[i].data, "backup", 6) == 0) { + + if (!(uscf->flags & NGX_HTTP_UPSTREAM_BACKUP)) { + goto invalid; + } + + us->backup = 1; + + continue; + } + if (ngx_strncmp(value[i].data, "down", 4) == 0) { if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) { 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 @@ -24,6 +24,7 @@ #define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000040 #define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000080 #define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000100 +#define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000 #define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000 diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -9,6 +9,7 @@ #include +static int ngx_http_upstream_cmp_servers(const void *one, const void *two); static ngx_uint_t ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers); @@ -20,15 +21,20 @@ ngx_http_upstream_init_round_robin(ngx_c ngx_url_t u; ngx_uint_t i, j, n; ngx_http_upstream_server_t *server; - ngx_http_upstream_rr_peers_t *peers; + ngx_http_upstream_rr_peers_t *peers, *backup; us->peer.init = ngx_http_upstream_init_round_robin_peer; if (us->servers) { - n = 0; server = us->servers->elts; + n = 0; + for (i = 0; i < us->servers->nelts; i++) { + if (server[i].backup) { + continue; + } + n += server[i].naddrs; } @@ -38,6 +44,7 @@ ngx_http_upstream_init_round_robin(ngx_c return NGX_ERROR; } + peers->single = (n == 1); peers->number = n; peers->name = &us->host; @@ -45,20 +52,81 @@ ngx_http_upstream_init_round_robin(ngx_c for (i = 0; i < us->servers->nelts; i++) { for (j = 0; j < server[i].naddrs; j++) { + if (server[i].backup) { + continue; + } + peers->peer[n].sockaddr = server[i].addrs[j].sockaddr; peers->peer[n].socklen = server[i].addrs[j].socklen; peers->peer[n].name = server[i].addrs[j].name; - peers->peer[n].weight = server[i].weight; - peers->peer[n].current_weight = server[i].weight; peers->peer[n].max_fails = server[i].max_fails; peers->peer[n].fail_timeout = server[i].fail_timeout; peers->peer[n].down = server[i].down; + peers->peer[n].weight = server[i].down ? 0 : server[i].weight; + peers->peer[n].current_weight = peers->peer[n].weight; n++; } } us->peer.data = peers; + ngx_sort(&peers->peer[0], (size_t) n, + sizeof(ngx_http_upstream_rr_peer_t), + ngx_http_upstream_cmp_servers); + + /* backup servers */ + + n = 0; + + for (i = 0; i < us->servers->nelts; i++) { + if (!server[i].backup) { + continue; + } + + n += server[i].naddrs; + } + + if (n == 0) { + return NGX_OK; + } + + backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) + + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); + if (backup == NULL) { + return NGX_ERROR; + } + + peers->single = 0; + backup->single = 0; + backup->number = n; + backup->name = &us->host; + + n = 0; + + for (i = 0; i < us->servers->nelts; i++) { + for (j = 0; j < server[i].naddrs; j++) { + if (!server[i].backup) { + continue; + } + + backup->peer[n].sockaddr = server[i].addrs[j].sockaddr; + backup->peer[n].socklen = server[i].addrs[j].socklen; + backup->peer[n].name = server[i].addrs[j].name; + backup->peer[n].weight = server[i].weight; + backup->peer[n].current_weight = server[i].weight; + backup->peer[n].max_fails = server[i].max_fails; + backup->peer[n].fail_timeout = server[i].fail_timeout; + backup->peer[n].down = server[i].down; + n++; + } + } + + peers->next = backup; + + ngx_sort(&backup->peer[0], (size_t) n, + sizeof(ngx_http_upstream_rr_peer_t), + ngx_http_upstream_cmp_servers); + return NGX_OK; } @@ -95,6 +163,7 @@ ngx_http_upstream_init_round_robin(ngx_c return NGX_ERROR; } + peers->single = (n == 1); peers->number = n; peers->name = &us->host; @@ -113,10 +182,24 @@ ngx_http_upstream_init_round_robin(ngx_c us->peer.data = peers; + /* implicitly defined upstream has no backup servers */ + return NGX_OK; } +static int +ngx_http_upstream_cmp_servers(const void *one, const void *two) +{ + ngx_http_upstream_rr_peer_t *first, *second; + + first = (ngx_http_upstream_rr_peer_t *) one; + second = (ngx_http_upstream_rr_peer_t *) two; + + return (first->weight < second->weight); +} + + ngx_int_t ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, ngx_http_upstream_srv_conf_t *us) @@ -171,11 +254,13 @@ ngx_http_upstream_get_round_robin_peer(n { ngx_http_upstream_rr_peer_data_t *rrp = data; - time_t now; - uintptr_t m; - ngx_uint_t i, n; - ngx_connection_t *c; - ngx_http_upstream_rr_peer_t *peer; + time_t now; + uintptr_t m; + ngx_int_t rc; + ngx_uint_t i, n; + ngx_connection_t *c; + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "get rr peer, try: %ui", pc->tries); @@ -207,7 +292,7 @@ ngx_http_upstream_get_round_robin_peer(n pc->cached = 0; pc->connection = NULL; - if (rrp->peers->number == 1) { + if (rrp->peers->single) { peer = &rrp->peers->peer[0]; } else { @@ -319,19 +404,53 @@ ngx_http_upstream_get_round_robin_peer(n /* ngx_unlock_mutex(rrp->peers->mutex); */ + if (pc->tries == 1 && rrp->peers->next) { + pc->tries += rrp->peers->next->number; + + n = rrp->peers->next->number / (8 * sizeof(uintptr_t)) + 1; + for (i = 0; i < n; i++) { + rrp->tried[i] = 0; + } + } + return NGX_OK; failed: + peers = rrp->peers; + + if (peers->next) { + + /* ngx_unlock_mutex(peers->mutex); */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pc->log, 0, "backup servers"); + + rrp->peers = peers->next; + pc->tries = rrp->peers->number; + + n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1; + for (i = 0; i < n; i++) { + rrp->tried[i] = 0; + } + + rc = ngx_http_upstream_get_round_robin_peer(pc, rrp); + + if (rc != NGX_BUSY) { + return rc; + } + + /* ngx_lock_mutex(peers->mutex); */ + } + /* all peers failed, mark them as live for quick recovery */ - for (i = 0; i < rrp->peers->number; i++) { - rrp->peers->peer[i].fails = 0; + for (i = 0; i < peers->number; i++) { + peers->peer[i].fails = 0; } - /* ngx_unlock_mutex(rrp->peers->mutex); */ + /* ngx_unlock_mutex(peers->mutex); */ - pc->name = rrp->peers->name; + pc->name = peers->name; return NGX_BUSY; } @@ -410,7 +529,7 @@ ngx_http_upstream_free_round_robin_peer( /* TODO: NGX_PEER_KEEPALIVE */ - if (rrp->peers->number == 1) { + if (rrp->peers->single) { pc->tries = 0; return; } diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -35,7 +35,10 @@ typedef struct { } ngx_http_upstream_rr_peer_t; -typedef struct { +typedef struct ngx_http_upstream_rr_peers_s ngx_http_upstream_rr_peers_t; + +struct ngx_http_upstream_rr_peers_s { + ngx_uint_t single; /* unsigned single:1; */ ngx_uint_t number; ngx_uint_t last_cached; @@ -44,8 +47,10 @@ typedef struct { ngx_str_t *name; + ngx_http_upstream_rr_peers_t *next; + ngx_http_upstream_rr_peer_t peer[1]; -} ngx_http_upstream_rr_peers_t; +}; typedef struct { diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -300,7 +300,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma return NGX_CONF_ERROR; } - ls->backlog = -1; + ls->backlog = NGX_LISTEN_BACKLOG; ls->rcvbuf = -1; ls->sndbuf = -1; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -21,6 +21,9 @@ typedef struct { ngx_str_t header; ngx_array_t *headers; + + u_char *file; + ngx_uint_t line; } ngx_mail_auth_http_conf_t; @@ -1311,6 +1314,9 @@ ngx_mail_auth_http_create_conf(ngx_conf_ ahcf->timeout = NGX_CONF_UNSET_MSEC; + ahcf->file = cf->conf_file->file.name.data; + ahcf->line = cf->conf_file->line; + return ahcf; } @@ -1330,6 +1336,14 @@ ngx_mail_auth_http_merge_conf(ngx_conf_t conf->peer = prev->peer; conf->host_header = prev->host_header; conf->uri = prev->uri; + + if (conf->peer == NULL) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"http_auth\" is defined for server in %s:%ui", + conf->file, conf->line); + + return NGX_CONF_ERROR; + } } ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); @@ -1383,11 +1397,18 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c u.uri_part = 1; u.one_addr = 1; + if (ngx_strncmp(u.url.data, "http://", 7) == 0) { + u.url.len -= 7; + u.url.data += 7; + } + if (ngx_parse_url(cf, &u) != NGX_OK) { if (u.err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s in auth_http \"%V\"", u.err, &u.url); } + + return NGX_CONF_ERROR; } ahcf->peer = u.addrs; 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 @@ -77,6 +77,9 @@ #endif +#define NGX_LISTEN_BACKLOG -1 + + #if (defined SO_ACCEPTFILTER && !defined NGX_HAVE_DEFERRED_ACCEPT) #define NGX_HAVE_DEFERRED_ACCEPT 1 #endif diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -78,6 +78,9 @@ extern ssize_t sendfile(int s, int fd, i #endif +#define NGX_LISTEN_BACKLOG 511 + + #if defined TCP_DEFER_ACCEPT && !defined NGX_HAVE_DEFERRED_ACCEPT #define NGX_HAVE_DEFERRED_ACCEPT 1 #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 @@ -88,6 +88,9 @@ #endif +#define NGX_LISTEN_BACKLOG 511 + + #if (__FreeBSD__) && (__FreeBSD_version < 400017) #include /* ALIGN() */ diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -82,6 +82,9 @@ #endif +#define NGX_LISTEN_BACKLOG 511 + + #ifndef NGX_HAVE_INHERITED_NONBLOCK #define NGX_HAVE_INHERITED_NONBLOCK 1 #endif