summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2007-08-15 12:44:43 +0000
committerJonathan Kolb <jon@b0g.us>2007-08-15 12:44:43 +0000
commit55c04d108b8c961e82c7a2907512b80a15cff5d1 (patch)
tree8acc5f2da0d5e00e14aeda2939ba8bc719c676bb
parentad5526a0773dea7fca82cca22433e2cb0b327837 (diff)
downloadnginx-55c04d108b8c961e82c7a2907512b80a15cff5d1.tar.gz
Changes with nginx 0.6.7 15 Aug 2007v0.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 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.
-rw-r--r--CHANGES44
-rw-r--r--CHANGES.ru44
-rw-r--r--auto/cc/sunc3
-rw-r--r--auto/init15
-rw-r--r--auto/install4
-rw-r--r--auto/options10
-rw-r--r--conf/nginx.conf4
-rw-r--r--src/core/nginx.h2
-rw-r--r--src/core/ngx_connection.c2
-rw-r--r--src/core/ngx_inet.c8
-rw-r--r--src/event/ngx_event.c19
-rw-r--r--src/event/ngx_event_connect.c2
-rw-r--r--src/http/modules/ngx_http_access_module.c10
-rw-r--r--src/http/modules/ngx_http_dav_module.c12
-rw-r--r--src/http/modules/ngx_http_empty_gif_module.c4
-rw-r--r--src/http/modules/ngx_http_flv_module.c4
-rw-r--r--src/http/modules/ngx_http_geo_module.c10
-rw-r--r--src/http/modules/ngx_http_headers_filter_module.c388
-rw-r--r--src/http/modules/ngx_http_memcached_module.c4
-rw-r--r--src/http/modules/ngx_http_realip_module.c10
-rw-r--r--src/http/modules/ngx_http_referer_module.c161
-rw-r--r--src/http/modules/ngx_http_static_module.c4
-rw-r--r--src/http/modules/ngx_http_stub_status_module.c4
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/modules/perl/nginx.xs23
-rw-r--r--src/http/ngx_http.c57
-rw-r--r--src/http/ngx_http.h3
-rw-r--r--src/http/ngx_http_core_module.c62
-rw-r--r--src/http/ngx_http_core_module.h17
-rw-r--r--src/http/ngx_http_request.c75
-rw-r--r--src/http/ngx_http_request.h10
-rw-r--r--src/http/ngx_http_request_body.c120
-rw-r--r--src/http/ngx_http_special_response.c2
-rw-r--r--src/http/ngx_http_upstream.c21
-rw-r--r--src/http/ngx_http_upstream.h1
-rw-r--r--src/http/ngx_http_upstream_round_robin.c149
-rw-r--r--src/http/ngx_http_upstream_round_robin.h9
-rw-r--r--src/mail/ngx_mail.c2
-rw-r--r--src/mail/ngx_mail_auth_http_module.c21
-rw-r--r--src/os/unix/ngx_freebsd_config.h3
-rw-r--r--src/os/unix/ngx_linux_config.h3
-rw-r--r--src/os/unix/ngx_posix_config.h3
-rw-r--r--src/os/unix/ngx_solaris_config.h3
43 files changed, 1063 insertions, 291 deletions
diff --git a/CHANGES b/CHANGES
index 8b8c1523c..e514d7dd8 100644
--- 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
index 94e8b21c4..d576fd8bd 100644
--- 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.
+ <br>
+
+ *) Исправление: теперь по умолчанию 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
index d464c6e11..0d7e2b2a7 100644
--- 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
index 6c52c21a2..e18044114 100644
--- 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
index e949aeccc..c85be1f4a 100644
--- a/auto/install
+++ b/auto/install
@@ -34,11 +34,11 @@ install: $NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \
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
index 0640f8c84..a9d7a2ae4 100644
--- 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
index 1edd0a63c..75dad9342 100644
--- 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
index dc09261ee..f18e06575 100644
--- 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
index 9d22ac60b..87219f236 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -123,7 +123,7 @@ ngx_set_inherited_sockets(ngx_cycle_t *cycle)
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
index de4cae280..31094ba59 100644
--- 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
index d32fb7ffd..7a856d409 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -1038,8 +1038,9 @@ ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
#if (NGX_DEBUG)
ngx_event_conf_t *ecf = conf;
- ngx_event_debug_t *dc;
+ ngx_int_t rc;
ngx_str_t *value;
+ ngx_event_debug_t *dc;
struct hostent *h;
ngx_inet_cidr_t in_cidr;
@@ -1056,13 +1057,21 @@ ngx_event_debug_connection(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (dc->addr != INADDR_NONE) {
dc->mask = 0xffffffff;
- return NGX_OK;
+ return NGX_CONF_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 (ngx_ptocidr(&value[1], &in_cidr) == 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 *cf, ngx_command_t *cmd, void *conf)
#endif
- return NGX_OK;
+ return NGX_CONF_OK;
}
diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c
index fae9c8c86..a2042c7c9 100644
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -85,6 +85,8 @@ ngx_event_connect_peer(ngx_peer_connection_t *pc)
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
index 2cd8a8f24..e4e87b243 100644
--- 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_command_t *cmd, void *conf)
{
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_command_t *cmd, void *conf)
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
index f3fbb9731..854627c78 100644
--- 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_request_t *r)
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_request_t *r, ngx_http_dav_loc_conf_t *dlcf)
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
index 050e75912..66ada088a 100644
--- 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_request_t *r)
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
index 6fda6baf1..cc258ea23 100644
--- 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 *r)
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
index 9c43bd716..bb9085e10 100644
--- 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_t *dummy, void *conf)
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
index 599bd14b7..81f4eb171 100644
--- 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 <ngx_http.h>
+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 {
- ngx_table_elt_t value;
- ngx_array_t *lengths;
- ngx_array_t *values;
-} ngx_http_header_val_t;
+ 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_str_t cache_control;
- ngx_array_t *headers;
+ 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_conf_t *cf, ngx_command_t *cmd,
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 ngx_http_next_header_filter;
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_t *r)
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) {
-
- 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 (ngx_http_set_expires(r, conf) != NGX_OK) {
+ return NGX_ERROR;
}
+ }
- 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 (conf->headers) {
+ h = conf->headers->elts;
+ for (i = 0; i < conf->headers->nelts; i++) {
- if (ngx_array_init(&r->headers_out.cache_control, r->pool,
- 1, sizeof(ngx_table_elt_t *))
- != NGX_OK)
- {
- return NGX_ERROR;
- }
+ if (h[i].lengths == NULL) {
+ value = h[i].value.value;
- ccp = ngx_array_push(&r->headers_out.cache_control);
- if (ccp == 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 = ngx_list_push(&r->headers_out.headers);
- if (cc == NULL) {
+ if (h[i].handler(r, &h[i], &value) != NGX_OK) {
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";
+ return ngx_http_next_header_filter(r);
+}
- 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";
+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;
- /* 10 years */
- cc->value.len = sizeof("max-age=315360000") - 1;
- cc->value.data = (u_char *) "max-age=315360000";
+ expires = r->headers_out.expires;
- } else {
- expires->value.data = ngx_palloc(r->pool, len);
- if (expires->value.data == NULL) {
- return NGX_ERROR;
- }
+ if (expires == NULL) {
- if (conf->expires == 0) {
- ngx_memcpy(expires->value.data, ngx_cached_http_time.data,
- ngx_cached_http_time.len + 1);
+ expires = ngx_list_push(&r->headers_out.headers);
+ if (expires == NULL) {
+ return NGX_ERROR;
+ }
- cc->value.len = sizeof("max-age=0") - 1;
- cc->value.data = (u_char *) "max-age=0";
+ r->headers_out.expires = expires;
- } 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;
- }
- }
- }
+ expires->hash = 1;
+ expires->key.len = sizeof("Expires") - 1;
+ expires->key.data = (u_char *) "Expires";
}
- if (conf->cache_control.len) {
+ len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT");
+ expires->value.len = len - 1;
- ccp = r->headers_out.cache_control.elts;
+ ccp = r->headers_out.cache_control.elts;
- if (ccp == NULL) {
+ 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;
- }
+ 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_t *r)
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->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;
- }
+ if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) {
+ expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT";
- out->hash = h[i].value.hash;
- out->key = h[i].value.key;
+ cc->value.len = sizeof("no-cache") - 1;
+ cc->value.data = (u_char *) "no-cache";
- if (h[i].lengths == NULL) {
- out->value = h[i].value.value;
- continue;
- }
+ return NGX_OK;
+ }
- if (ngx_http_script_run(r, &out->value, h[i].lengths->elts, 0,
- h[i].values->elts)
- == NULL)
- {
- return NGX_ERROR;
- }
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+
+ 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;
+}
+
+
+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 *cf)
/*
* 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 *cf, void *parent, void *child)
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_command_t *cmd, void *conf)
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_command_t *cmd, void *conf)
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
index f7205418c..013b5cbb8 100644
--- 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_request_t *r)
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
index ffb2028bf..4de4c1317 100644
--- 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_command_t *cmd, void *conf)
{
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_command_t *cmd, void *conf)
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
index 8559521e2..bf87a1bfc 100644
--- 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_conf_t *cf, ngx_command_t *cmd,
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_request_t *r, ngx_http_variable_value_t *v,
}
}
- 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, &regex[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, ngx_command_t *cmd, void *conf)
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, ngx_command_t *cmd, void *conf)
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_hash_keys_arrays_t *keys,
}
+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
index 8f355dcf9..b94ebf230 100644
--- 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_t *r)
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
index 4fe9c04d5..6cdf8513c 100644
--- 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(ngx_http_request_t *r)
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
index ca86b7840..227c08c9a 100644
--- 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
index dd01f3b3c..7423daa93 100644
--- 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 = 0)
(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
index dfe6eff70..97a2c193c 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -98,6 +98,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
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_command_t *cmd, void *conf)
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_command_t *cmd, void *conf)
}
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_command_t *cmd, void *conf)
}
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_http_conf_in_port_t *in_port,
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_http_conf_in_port_t *in_port,
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_http_conf_in_addr_t *in_addr,
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_http_conf_in_addr_t *in_addr,
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
index 266873ad6..8b04b7a35 100644
--- 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_t t);
-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
index 0e732cfe2..ab9812e9b 100644
--- 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_request_t *r,
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_request_t *r,
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 *cf, void *parent, void *child)
#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_command_t *cmd, void *conf)
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_command_t *cmd, void *conf)
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, ngx_command_t *cmd, void *conf)
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, ngx_command_t *cmd, void *conf)
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
index dc443f64a..ec96c3ee1 100644
--- 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 {
- ngx_str_t name;
+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_http_server_name_t;
+ ngx_str_t name;
+};
typedef struct {
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 21812e636..f52a764e4 100644
--- 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_event_t *ev);
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_request_t *r)
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;
+#if (NGX_PCRE)
+ ngx_int_t n;
+ ngx_uint_t i;
+ ngx_str_t name;
+ ngx_http_server_name_t *sn;
+#endif
- vn = r->virtual_names;
-
- cscf = ngx_hash_find_combined(vn, hash, host, len);
+ 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_request_t *r)
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 *r)
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_t *r)
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_t *r)
}
}
- 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)
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
index b440f14fd..0b269a893 100644
--- 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
index 494f48416..1ebb2e5f9 100644
--- 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_body_handler(ngx_http_request_t *r);
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_request_t *r, ngx_chain_t *body)
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 *r)
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)
}
}
- 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;
+
+ if (rev->timedout) {
+ c->timedout = 1;
+ c->error = 1;
+ ngx_http_finalize_request(r, 0);
+ return;
+ }
- rc = ngx_http_read_discarded_body(r);
+ if (r->lingering_time) {
+ timer = r->lingering_time - ngx_time();
- if (rc == NGX_AGAIN) {
- if (ngx_handle_read_event(r->connection->read, 0) == NGX_ERROR) {
- ngx_http_finalize_request(r, rc);
+ if (timer <= 0) {
+ r->discard_body = 0;
+ ngx_http_finalize_request(r, 0);
return;
}
+
+ } else {
+ timer = 0;
}
- if (rc != NGX_OK) {
+ 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;
+ }
+
+ /* 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_request_t *r)
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;
- }
-
- 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);
+ do {
+ if (r->headers_in.content_length_n == 0) {
+ r->read_event_handler = ngx_http_block_reading;
+ return NGX_OK;
+ }
- if (n == NGX_ERROR) {
+ 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;
- 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
- */
+ if (n == NGX_ERROR) {
+ r->connection->error = 1;
+ return NGX_OK;
+ }
- 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;
+ } while (r->connection->read->ready);
- return NGX_OK;
+ return NGX_AGAIN;
}
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 1797603a0..944bf335e 100644
--- 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_http_request_t *r, ngx_int_t error)
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
index bc4567458..fa847729c 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -565,9 +565,11 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
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_request_t *r, ngx_http_upstream_t *u)
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_t *r, ngx_http_upstream_t *u,
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, ngx_command_t *cmd, void *conf)
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
index b3bb1b4fd..5c77be39c 100644
--- 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
index 6756d2bc2..bdeeb16c8 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -9,6 +9,7 @@
#include <ngx_http.h>
+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_conf_t *cf,
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_conf_t *cf,
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_conf_t *cf,
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_conf_t *cf,
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_conf_t *cf,
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(ngx_peer_connection_t *pc, void *data)
{
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(ngx_peer_connection_t *pc, void *data)
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(ngx_peer_connection_t *pc, void *data)
/* 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(ngx_peer_connection_t *pc, void *data,
/* 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
index 15e69153a..a9ab1cf6e 100644
--- 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
index ec74e6f03..a39bec4a4 100644
--- a/src/mail/ngx_mail.c
+++ b/src/mail/ngx_mail.c
@@ -300,7 +300,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
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
index c7e0fc038..52031b340 100644
--- 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_t *cf)
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 *cf, void *parent, void *child)
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_command_t *cmd, void *conf)
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
index 0bf4fd525..818e230ba 100644
--- 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
index 980e05d67..3e0475ffc 100644
--- 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, int32_t *offset, size_t size);
#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
index 8a9509960..f79657654 100644
--- 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 <sys/param.h> /* ALIGN() */
diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h
index 9183bb360..989a30e2c 100644
--- 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