summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES25
-rw-r--r--CHANGES.ru26
-rw-r--r--auto/modules6
-rw-r--r--auto/options3
-rw-r--r--auto/sources4
-rw-r--r--src/core/nginx.h2
-rw-r--r--src/core/ngx_config.h2
-rw-r--r--src/core/ngx_connection.c2
-rw-r--r--src/event/ngx_event_accept.c2
-rw-r--r--src/http/modules/ngx_http_chunked_filter_module.c3
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c4
-rw-r--r--src/http/modules/ngx_http_log_module.c45
-rw-r--r--src/http/modules/ngx_http_proxy_module.c4
-rw-r--r--src/http/modules/ngx_http_range_filter_module.c6
-rw-r--r--src/http/modules/ngx_http_realip_module.c121
-rw-r--r--src/http/modules/ngx_http_secure_link_module.c193
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/ngx_http.h3
-rw-r--r--src/http/ngx_http_core_module.c31
-rw-r--r--src/http/ngx_http_core_module.h2
-rw-r--r--src/http/ngx_http_parse.c18
-rw-r--r--src/http/ngx_http_request.c56
-rw-r--r--src/http/ngx_http_request.h1
-rw-r--r--src/http/ngx_http_upstream.c184
-rw-r--r--src/http/ngx_http_upstream.h21
-rw-r--r--src/http/ngx_http_variables.c60
-rw-r--r--src/os/unix/ngx_files.h2
27 files changed, 690 insertions, 138 deletions
diff --git a/CHANGES b/CHANGES
index c910c170d..6fe31a2ea 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,29 @@
+Changes with nginx 0.7.18 13 Oct 2008
+
+ *) Change: the "underscores_in_headers" directive; now nginx does not
+ allows underscores in a client request header line names.
+
+ *) Feature: the ngx_http_secure_link_module.
+
+ *) Feature: the "real_ip_header" directive supports any header.
+
+ *) Feature: the "log_subrequest" directive.
+
+ *) Feature: the $realpath_root variable.
+
+ *) Feature: the "http_502" and "http_504" parameters of the
+ "proxy_next_upstream" directive.
+
+ *) Bugfix: the "http_503" parameter of the "proxy_next_upstream" or
+ "fastcgi_next_upstream" directives did not work.
+
+ *) Bugfix: nginx might send a "Transfer-Encoding: chunked" heaer line
+ for HEAD requests.
+
+ *) Bugfix: now accept threshold depends on worker_connections.
+
+
Changes with nginx 0.7.17 15 Sep 2008
*) Feature: now the "directio" directive works on Linux.
diff --git a/CHANGES.ru b/CHANGES.ru
index 34a90c257..5ddf630b9 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,30 @@
+Изменения в nginx 0.7.18 13.10.2008
+
+ *) Изменение: директива underscores_in_headers; теперь nginx по
+ умолчанию не разрешает подчёркивания в именах строк в заголовке
+ запроса клиента.
+
+ *) Добавление: модуль ngx_http_secure_link_module.
+
+ *) Добавление: директива real_ip_header поддерживает любой заголовок.
+
+ *) Добавление: директива log_subrequest.
+
+ *) Добавление: переменная $realpath_root.
+
+ *) Добавление: параметры http_502 и http_504 в директиве
+ proxy_next_upstream.
+
+ *) Исправление: параметр http_503 в директивах proxy_next_upstream или
+ fastcgi_next_upstream не работал.
+
+ *) Исправление: nginx мог выдавать строку "Transfer-Encoding: chunked"
+ для запросов HEAD.
+
+ *) Исправление: теперь accept-лимит зависит от числа worker_connections.
+
+
Изменения в nginx 0.7.17 15.09.2008
*) Добавление: директива directio теперь работает на Linux.
diff --git a/auto/modules b/auto/modules
index f6fde2452..70b2e6055 100644
--- a/auto/modules
+++ b/auto/modules
@@ -284,6 +284,12 @@ if [ $HTTP_BROWSER = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_BROWSER_SRCS"
fi
+if [ $HTTP_SECURE_LINK = YES ]; then
+ USE_MD5=YES
+ HTTP_MODULES="$HTTP_MODULES $HTTP_SECURE_LINK_MODULE"
+ HTTP_SRCS="$HTTP_SRCS $HTTP_SECURE_LINK_SRCS"
+fi
+
if [ $HTTP_FLV = YES ]; then
HTTP_MODULES="$HTTP_MODULES $HTTP_FLV_MODULE"
HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS"
diff --git a/auto/options b/auto/options
index 01b1ca2e0..aba80c4ec 100644
--- a/auto/options
+++ b/auto/options
@@ -77,6 +77,7 @@ HTTP_MEMCACHED=YES
HTTP_LIMIT_ZONE=YES
HTTP_EMPTY_GIF=YES
HTTP_BROWSER=YES
+HTTP_SECURE_LINK=NO
HTTP_FLV=NO
HTTP_GZIP_STATIC=NO
HTTP_UPSTREAM_IP_HASH=YES
@@ -173,6 +174,7 @@ do
--with-http_flv_module) HTTP_FLV=YES ;;
--with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;;
--with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;;
+ --with-http_secure_link_module) HTTP_SECURE_LINK=YES ;;
--without-http_charset_module) HTTP_CHARSET=NO ;;
--without-http_gzip_module) HTTP_GZIP=NO ;;
@@ -290,6 +292,7 @@ cat << END
--with-http_flv_module enable ngx_http_flv_module
--with-http_gzip_static_module enable ngx_http_gzip_static_module
--with-http_random_index_module enable ngx_http_random_index_module
+ --with-http_secure_link_module enable ngx_http_secure_link_module
--with-http_stub_status_module enable ngx_http_stub_status_module
--without-http_charset_module disable ngx_http_charset_module
diff --git a/auto/sources b/auto/sources
index 491c2e77b..68ec98fd3 100644
--- a/auto/sources
+++ b/auto/sources
@@ -425,6 +425,10 @@ HTTP_BROWSER_MODULE=ngx_http_browser_module
HTTP_BROWSER_SRCS=src/http/modules/ngx_http_browser_module.c
+HTTP_SECURE_LINK_MODULE=ngx_http_secure_link_module
+HTTP_SECURE_LINK_SRCS=src/http/modules/ngx_http_secure_link_module.c
+
+
HTTP_FLV_MODULE=ngx_http_flv_module
HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c
diff --git a/src/core/nginx.h b/src/core/nginx.h
index e86bae6ca..319b39d36 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VERSION "0.7.17"
+#define NGINX_VERSION "0.7.19"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h
index 5861bfd09..ab73079a6 100644
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -110,8 +110,6 @@ typedef intptr_t ngx_flag_t;
#define ngx_inline inline
#endif
-#define NGX_ACCEPT_THRESHOLD 100
-
#ifndef INADDR_NONE /* Solaris */
#define INADDR_NONE ((unsigned int) -1)
#endif
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 226dc1ec8..28c904b5e 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -593,7 +593,7 @@ ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
if (c == NULL) {
ngx_log_error(NGX_LOG_ALERT, log, 0,
- "%ui worker_connections is not enough",
+ "%ui worker_connections are not enough",
ngx_cycle->connection_n);
/* ngx_mutex_unlock */
diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c
index 39b651539..379abb9c3 100644
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -82,7 +82,7 @@ ngx_event_accept(ngx_event_t *ev)
ngx_atomic_fetch_add(ngx_stat_accepted, 1);
#endif
- ngx_accept_disabled = NGX_ACCEPT_THRESHOLD
+ ngx_accept_disabled = ngx_cycle->connection_n / 8
- ngx_cycle->free_connection_n;
c = ngx_get_connection(s, ev->log);
diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c
index 3cc20ebfb..846053ff4 100644
--- a/src/http/modules/ngx_http_chunked_filter_module.c
+++ b/src/http/modules/ngx_http_chunked_filter_module.c
@@ -53,7 +53,8 @@ ngx_http_chunked_header_filter(ngx_http_request_t *r)
if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED
|| r->headers_out.status == NGX_HTTP_NO_CONTENT
|| r->headers_out.status == NGX_HTTP_CREATED
- || r != r->main)
+ || r != r->main
+ || (r->method & NGX_HTTP_HEAD))
{
return ngx_http_next_header_filter(r);
}
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 049c1130b..b4a07d011 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1031,7 +1031,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
part_start = u->buffer.pos;
- rc = ngx_http_parse_header_line(r, &u->buffer);
+ rc = ngx_http_parse_header_line(r, &u->buffer, 1);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http fastcgi parser: %d", rc);
@@ -1076,7 +1076,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
f->split_parts->nelts = 0;
- rc = ngx_http_parse_header_line(r, &buf);
+ rc = ngx_http_parse_header_line(r, &buf, 1);
h->key.len = r->header_name_end - r->header_name_start;
h->key.data = r->header_name_start;
diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c
index 775279c88..80bf22180 100644
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -28,6 +28,7 @@ struct ngx_http_log_op_s {
typedef struct {
ngx_str_t name;
+ ngx_array_t *flushes;
ngx_array_t *ops; /* array of ngx_http_log_op_t */
} ngx_http_log_fmt_t;
@@ -49,7 +50,7 @@ typedef struct {
ngx_http_log_script_t *script;
time_t disk_full_time;
time_t error_log_time;
- ngx_array_t *ops; /* array of ngx_http_log_op_t */
+ ngx_http_log_fmt_t *format;
} ngx_http_log_t;
@@ -113,7 +114,7 @@ static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_log_compile_format(ngx_conf_t *cf,
- ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
+ ngx_array_t *flushes, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s);
static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static ngx_int_t ngx_http_log_init(ngx_conf_t *cf);
@@ -242,9 +243,11 @@ ngx_http_log_handler(ngx_http_request_t *r)
continue;
}
+ ngx_http_script_flush_no_cacheable_variables(r, log[l].format->flushes);
+
len = 0;
- op = log[l].ops->elts;
- for (i = 0; i < log[l].ops->nelts; i++) {
+ op = log[l].format->ops->elts;
+ for (i = 0; i < log[l].format->ops->nelts; i++) {
if (op[i].len == 0) {
len += op[i].getlen(r, op[i].data);
@@ -271,7 +274,7 @@ ngx_http_log_handler(ngx_http_request_t *r)
p = file->pos;
- for (i = 0; i < log[l].ops->nelts; i++) {
+ for (i = 0; i < log[l].format->ops->nelts; i++) {
p = op[i].run(r, p, &op[i]);
}
@@ -290,7 +293,7 @@ ngx_http_log_handler(ngx_http_request_t *r)
p = line;
- for (i = 0; i < log[l].ops->nelts; i++) {
+ for (i = 0; i < log[l].format->ops->nelts; i++) {
p = op[i].run(r, p, &op[i]);
}
@@ -726,6 +729,8 @@ ngx_http_log_create_main_conf(ngx_conf_t *cf)
fmt->name.len = sizeof("combined") - 1;
fmt->name.data = (u_char *) "combined";
+ fmt->flushes = NULL;
+
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
if (fmt->ops == NULL) {
return NGX_CONF_ERROR;
@@ -806,7 +811,7 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
fmt = lmcf->formats.elts;
/* the default "combined" format */
- log->ops = fmt[0].ops;
+ log->format = &fmt[0];
lmcf->combined_used = 1;
return NGX_CONF_OK;
@@ -900,7 +905,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (fmt[i].name.len == name.len
&& ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
{
- log->ops = fmt[i].ops;
+ log->format = &fmt[i];
goto buffer;
}
}
@@ -985,22 +990,28 @@ ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
fmt->name = value[1];
+ fmt->flushes = ngx_array_create(cf->pool, 4, sizeof(ngx_int_t));
+ if (fmt->flushes == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t));
if (fmt->ops == NULL) {
return NGX_CONF_ERROR;
}
- return ngx_http_log_compile_format(cf, fmt->ops, cf->args, 2);
+ return ngx_http_log_compile_format(cf, fmt->flushes, fmt->ops, cf->args, 2);
}
static char *
-ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops,
- ngx_array_t *args, ngx_uint_t s)
+ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
+ ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s)
{
u_char *data, *p, ch;
size_t i, len;
ngx_str_t *value, var;
+ ngx_int_t *flush;
ngx_uint_t bracket;
ngx_http_log_op_t *op;
ngx_http_log_var_t *v;
@@ -1114,6 +1125,16 @@ ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops,
return NGX_CONF_ERROR;
}
+ if (flushes) {
+
+ flush = ngx_array_push(flushes);
+ if (flush == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ *flush = op->data; /* variable index */
+ }
+
found:
continue;
@@ -1299,7 +1320,7 @@ ngx_http_log_init(ngx_conf_t *cf)
*value = ngx_http_combined_fmt;
fmt = lmcf->formats.elts;
- if (ngx_http_log_compile_format(cf, fmt->ops, &a, 0)
+ if (ngx_http_log_compile_format(cf, NULL, fmt->ops, &a, 0)
!= NGX_CONF_OK)
{
return NGX_ERROR;
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 6c0e28a34..f3d747f0f 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -147,7 +147,9 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
{ ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT },
{ ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER },
{ ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 },
+ { ngx_string("http_502"), NGX_HTTP_UPSTREAM_FT_HTTP_502 },
{ ngx_string("http_503"), NGX_HTTP_UPSTREAM_FT_HTTP_503 },
+ { ngx_string("http_504"), NGX_HTTP_UPSTREAM_FT_HTTP_504 },
{ ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 },
{ ngx_string("off"), NGX_HTTP_UPSTREAM_FT_OFF },
{ ngx_null_string, 0 }
@@ -1214,7 +1216,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
for ( ;; ) {
- rc = ngx_http_parse_header_line(r, &r->upstream->buffer);
+ rc = ngx_http_parse_header_line(r, &r->upstream->buffer, 1);
if (rc == NGX_OK) {
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 377ca9b28..4a15637f5 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -654,7 +654,13 @@ ngx_http_range_singlepart_body(ngx_http_request_t *r,
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http range body skip");
+ if (buf->in_file) {
+ buf->file_pos = buf->file_last;
+ }
+
buf->pos = buf->last;
+ buf->sync = 1;
+
continue;
}
diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c
index 5a79e7483..44c74a182 100644
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -9,6 +9,11 @@
#include <ngx_http.h>
+#define NGX_HTTP_REALIP_XREALIP 0
+#define NGX_HTTP_REALIP_XFWD 1
+#define NGX_HTTP_REALIP_HEADER 2
+
+
/* AF_INET only */
typedef struct {
@@ -19,7 +24,9 @@ typedef struct {
typedef struct {
ngx_array_t *from; /* array of ngx_http_realip_from_t */
- ngx_uint_t xfwd;
+ ngx_uint_t type;
+ ngx_uint_t hash;
+ ngx_str_t header;
} ngx_http_realip_loc_conf_t;
@@ -34,19 +41,13 @@ static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r);
static void ngx_http_realip_cleanup(void *data);
static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void *ngx_http_realip_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_realip_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
static ngx_int_t ngx_http_realip_init(ngx_conf_t *cf);
-static ngx_conf_enum_t ngx_http_realip_header[] = {
- { ngx_string("X-Forwarded-For"), 1 },
- { ngx_string("X-Real-IP"), 0 },
- { ngx_null_string, 0 }
-};
-
-
static ngx_command_t ngx_http_realip_commands[] = {
{ ngx_string("set_real_ip_from"),
@@ -58,10 +59,10 @@ static ngx_command_t ngx_http_realip_commands[] = {
{ ngx_string("real_ip_header"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_enum_slot,
+ ngx_http_realip,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_realip_loc_conf_t, xfwd),
- &ngx_http_realip_header },
+ 0,
+ NULL },
ngx_null_command
};
@@ -105,7 +106,9 @@ ngx_http_realip_handler(ngx_http_request_t *r)
u_char *ip, *p;
size_t len;
in_addr_t addr;
- ngx_uint_t i;
+ ngx_uint_t i, hash;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
struct sockaddr_in *sin;
ngx_connection_t *c;
ngx_pool_cleanup_t *cln;
@@ -130,7 +133,10 @@ ngx_http_realip_handler(ngx_http_request_t *r)
return NGX_DECLINED;
}
- if (rlcf->xfwd == 0) {
+ switch (rlcf->type) {
+
+ case NGX_HTTP_REALIP_XREALIP:
+
if (r->headers_in.x_real_ip == NULL) {
return NGX_DECLINED;
}
@@ -138,7 +144,10 @@ ngx_http_realip_handler(ngx_http_request_t *r)
len = r->headers_in.x_real_ip->value.len;
ip = r->headers_in.x_real_ip->value.data;
- } else {
+ break;
+
+ case NGX_HTTP_REALIP_XFWD:
+
if (r->headers_in.x_forwarded_for == NULL) {
return NGX_DECLINED;
}
@@ -154,8 +163,46 @@ ngx_http_realip_handler(ngx_http_request_t *r)
break;
}
}
+
+ break;
+
+ default: /* NGX_HTTP_REALIP_HEADER */
+
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ hash = rlcf->hash;
+ len = rlcf->header.len;
+ p = rlcf->header.data;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ if (hash == header[i].hash
+ && len == header[i].key.len
+ && ngx_strncmp(p, header[i].lowcase_key, len) == 0)
+ {
+ len = header[i].value.len;
+ ip = header[i].value.data;
+
+ goto found;
+ }
+ }
+
+ return NGX_DECLINED;
}
+found:
+
c = r->connection;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "realip: \"%s\"", ip);
@@ -231,10 +278,10 @@ 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;
+ ngx_int_t rc;
+ ngx_str_t *value;
+ ngx_inet_cidr_t in_cidr;
+ ngx_http_realip_from_t *from;
if (rlcf->from == NULL) {
rlcf->from = ngx_array_create(cf->pool, 2,
@@ -271,6 +318,33 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
+static char *
+ngx_http_realip(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_realip_loc_conf_t *rlcf = conf;
+
+ ngx_str_t *value;
+
+ value = cf->args->elts;
+
+ if (ngx_strcmp(value[1].data, "X-Real-IP") == 0) {
+ rlcf->type = NGX_HTTP_REALIP_XREALIP;
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_strcmp(value[1].data, "X-Forwarded-For") == 0) {
+ rlcf->type = NGX_HTTP_REALIP_XFWD;
+ return NGX_CONF_OK;
+ }
+
+ rlcf->type = NGX_HTTP_REALIP_HEADER;
+ rlcf->hash = ngx_hash_strlow(value[1].data, value[1].data, value[1].len);
+ rlcf->header = value[1];
+
+ return NGX_CONF_OK;
+}
+
+
static void *
ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
{
@@ -285,9 +359,11 @@ ngx_http_realip_create_loc_conf(ngx_conf_t *cf)
* set by ngx_pcalloc():
*
* conf->from = NULL;
+ * conf->hash = 0;
+ * conf->header = { 0, NULL };
*/
- conf->xfwd = NGX_CONF_UNSET_UINT;
+ conf->type = NGX_CONF_UNSET_UINT;
return conf;
}
@@ -303,7 +379,12 @@ ngx_http_realip_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->from = prev->from;
}
- ngx_conf_merge_uint_value(conf->xfwd, prev->xfwd, 0);
+ ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP);
+
+ if (conf->header.len == 0) {
+ conf->hash = prev->hash;
+ conf->header = prev->header;
+ }
return NGX_CONF_OK;
}
diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c
new file mode 100644
index 000000000..0b2a4451a
--- /dev/null
+++ b/src/http/modules/ngx_http_secure_link_module.c
@@ -0,0 +1,193 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <ngx_md5.h>
+
+
+typedef struct {
+ ngx_str_t secret;
+} ngx_http_secure_link_conf_t;
+
+
+static void *ngx_http_secure_link_create_conf(ngx_conf_t *cf);
+static char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+static ngx_int_t ngx_http_secure_link_add_variables(ngx_conf_t *cf);
+
+
+static ngx_command_t ngx_http_secure_link_commands[] = {
+
+ { ngx_string("secure_link_secret"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_secure_link_conf_t, secret),
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_secure_link_module_ctx = {
+ ngx_http_secure_link_add_variables, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_secure_link_create_conf, /* create location configuration */
+ ngx_http_secure_link_merge_conf /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_secure_link_module = {
+ NGX_MODULE_V1,
+ &ngx_http_secure_link_module_ctx, /* module context */
+ ngx_http_secure_link_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_str_t ngx_http_secure_link = ngx_string("secure_link");
+
+
+static ngx_int_t
+ngx_http_secure_link_variable(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ u_char *p, *start, *end, *last;
+ size_t len;
+ ngx_int_t n;
+ ngx_uint_t i;
+ ngx_md5_t md5;
+ ngx_http_secure_link_conf_t *conf;
+ u_char hash[16];
+
+ conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
+
+ if (conf->secret.len == 0) {
+ goto not_found;
+ }
+
+ p = &r->unparsed_uri.data[1];
+ last = r->unparsed_uri.data + r->unparsed_uri.len;
+
+ while (p < last) {
+ if (*p++ == '/') {
+ start = p;
+ goto md5_start;
+ }
+ }
+
+ goto not_found;
+
+md5_start:
+
+ while (p < last) {
+ if (*p++ == '/') {
+ end = p - 1;
+ goto url_start;
+ }
+ }
+
+ goto not_found;
+
+url_start:
+
+ len = last - p;
+
+ if (end - start != 32 || len < 3) {
+ goto not_found;
+ }
+
+ ngx_md5_init(&md5);
+ ngx_md5_update(&md5, p, len);
+ ngx_md5_update(&md5, conf->secret.data, conf->secret.len);
+ ngx_md5_final(hash, &md5);
+
+ for (i = 0; i < 16; i++) {
+ n = ngx_hextoi(&start[2 * i], 2);
+ if (n == NGX_ERROR || n != hash[i]) {
+ goto not_found;
+ }
+ }
+
+ v->len = len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = p;
+
+ return NGX_OK;
+
+not_found:
+
+ v->not_found = 1;
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_http_secure_link_create_conf(ngx_conf_t *cf)
+{
+ ngx_http_secure_link_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
+ if (conf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->secret = { 0, NULL }
+ */
+
+ return conf;
+}
+
+
+static char *
+ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_secure_link_conf_t *prev = parent;
+ ngx_http_secure_link_conf_t *conf = child;
+
+ ngx_conf_merge_str_value(conf->secret, prev->secret, "");
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_secure_link_add_variables(ngx_conf_t *cf)
+{
+ ngx_http_variable_t *var;
+
+ var = ngx_http_add_variable(cf, &ngx_http_secure_link, NGX_HTTP_VAR_NOHASH);
+ if (var == NULL) {
+ return NGX_ERROR;
+ }
+
+ var->get_handler = ngx_http_secure_link_variable;
+
+ return NGX_OK;
+}
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index c837bd8b2..4b93284e0 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.7.17';
+our $VERSION = '0.7.19';
require XSLoader;
XSLoader::load('nginx', $VERSION);
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 762d85c74..79b218716 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -72,7 +72,8 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r,
ngx_uint_t merge_slashes);
ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ngx_str_t *args, ngx_uint_t *flags);
-ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b);
+ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
+ ngx_uint_t allow_underscores);
ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers,
ngx_str_t *name, ngx_str_t *value);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index e1d5a8f55..1d8a55222 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -231,6 +231,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_srv_conf_t, merge_slashes),
NULL },
+ { ngx_string("underscores_in_headers"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ offsetof(ngx_http_core_srv_conf_t, underscores_in_headers),
+ NULL },
+
{ ngx_string("location"),
NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
ngx_http_core_location,
@@ -487,6 +494,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, log_not_found),
NULL },
+ { ngx_string("log_subrequest"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_core_loc_conf_t, log_subrequest),
+ NULL },
+
{ ngx_string("recursive_error_pages"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -2527,6 +2541,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t *cf)
cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE;
cscf->ignore_invalid_headers = NGX_CONF_UNSET;
cscf->merge_slashes = NGX_CONF_UNSET;
+ cscf->underscores_in_headers = NGX_CONF_UNSET;
return cscf;
}
@@ -2605,6 +2620,9 @@ ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1);
+ ngx_conf_merge_value(conf->underscores_in_headers,
+ prev->underscores_in_headers, 0);
+
return NGX_CONF_OK;
}
@@ -2663,6 +2681,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
lcf->msie_padding = NGX_CONF_UNSET;
lcf->msie_refresh = NGX_CONF_UNSET;
lcf->log_not_found = NGX_CONF_UNSET;
+ lcf->log_subrequest = NGX_CONF_UNSET;
lcf->recursive_error_pages = NGX_CONF_UNSET;
lcf->server_tokens = NGX_CONF_UNSET;
lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
@@ -2887,6 +2906,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
ngx_conf_merge_value(conf->msie_refresh, prev->msie_refresh, 0);
ngx_conf_merge_value(conf->log_not_found, prev->log_not_found, 1);
+ ngx_conf_merge_value(conf->log_subrequest, prev->log_subrequest, 0);
ngx_conf_merge_value(conf->recursive_error_pages,
prev->recursive_error_pages, 0);
ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1);
@@ -3271,6 +3291,17 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
+ if (ngx_strstr(value[1].data, "$realpath_root")
+ || ngx_strstr(value[1].data, "${realpath_root}"))
+ {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the $realpath_root variable may not be used "
+ "in the \"%V\" directive",
+ &cmd->name);
+
+ return NGX_CONF_ERROR;
+ }
+
lcf->alias = alias;
lcf->root = value[1];
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index a3d8940a9..99b5bd310 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -155,6 +155,7 @@ typedef struct {
ngx_flag_t ignore_invalid_headers;
ngx_flag_t merge_slashes;
+ ngx_flag_t underscores_in_headers;
ngx_http_core_loc_conf_t **named_locations;
} ngx_http_core_srv_conf_t;
@@ -310,6 +311,7 @@ struct ngx_http_core_loc_conf_s {
ngx_flag_t msie_padding; /* msie_padding */
ngx_flag_t msie_refresh; /* msie_refresh */
ngx_flag_t log_not_found; /* log_not_found */
+ ngx_flag_t log_subrequest; /* log_subrequest */
ngx_flag_t recursive_error_pages; /* recursive_error_pages */
ngx_flag_t server_tokens; /* server_tokens */
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 2fce7acac..b08d5eaa7 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -700,7 +700,8 @@ done:
ngx_int_t
-ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
+ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
+ ngx_uint_t allow_underscores)
{
u_char c, ch, *p;
ngx_uint_t hash, i;
@@ -720,7 +721,7 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
static u_char lowcase[] =
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0"
- "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_"
+ "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
"\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
@@ -779,6 +780,19 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b)
break;
}
+ if (ch == '_') {
+ if (allow_underscores) {
+ hash = ngx_hash(hash, ch);
+ r->lowcase_header[i++] = ch;
+ i &= (NGX_HTTP_LC_HEADER_LEN - 1);
+
+ } else {
+ r->invalid_header = 1;
+ }
+
+ break;
+ }
+
if (ch == ':') {
r->header_name_end = p;
state = sw_space_before_value;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index ae3bb03d5..e1f0ae793 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -47,6 +47,7 @@ static void ngx_http_lingering_close_handler(ngx_event_t *ev);
static ngx_int_t ngx_http_post_action(ngx_http_request_t *r);
static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error);
static void ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error);
+static void ngx_http_log_request(ngx_http_request_t *r);
static void ngx_http_close_connection(ngx_connection_t *c);
static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len);
@@ -902,7 +903,8 @@ ngx_http_process_request_headers(ngx_event_t *rev)
}
}
- rc = ngx_http_parse_header_line(r, r->header_in);
+ rc = ngx_http_parse_header_line(r, r->header_in,
+ cscf->underscores_in_headers);
if (rc == NGX_OK) {
@@ -1758,6 +1760,17 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
return;
}
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (r != r->main && !r->logged) {
+
+ if (clcf->log_subrequest) {
+ ngx_http_log_request(r);
+ }
+
+ r->logged = 1;
+ }
+
if (r != r->main || rc == NGX_AGAIN) {
if (ngx_http_set_write_handler(r) != NGX_OK) {
return;
@@ -1856,8 +1869,6 @@ ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
return;
}
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
if (!ngx_terminate
&& !ngx_exiting
&& r->keepalive
@@ -2603,14 +2614,11 @@ ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error)
static void
ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error)
{
- ngx_log_t *log;
- ngx_uint_t i, n;
- struct linger linger;
- ngx_http_cleanup_t *cln;
- ngx_http_log_ctx_t *ctx;
- ngx_http_handler_pt *log_handler;
- ngx_http_core_loc_conf_t *clcf;
- ngx_http_core_main_conf_t *cmcf;
+ ngx_log_t *log;
+ struct linger linger;
+ ngx_http_cleanup_t *cln;
+ ngx_http_log_ctx_t *ctx;
+ ngx_http_core_loc_conf_t *clcf;
log = r->connection->log;
@@ -2645,13 +2653,7 @@ ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error)
log->action = "logging request";
- cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
- log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts;
- n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts;
- for (i = 0; i < n; i++) {
- log_handler[i](r);
- }
+ ngx_http_log_request(r);
log->action = "closing request";
@@ -2684,6 +2686,24 @@ ngx_http_request_done(ngx_http_request_t *r, ngx_int_t error)
static void
+ngx_http_log_request(ngx_http_request_t *r)
+{
+ ngx_uint_t i, n;
+ ngx_http_handler_pt *log_handler;
+ ngx_http_core_main_conf_t *cmcf;
+
+ cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+ log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts;
+ n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts;
+
+ for (i = 0; i < n; i++) {
+ log_handler[i](r);
+ }
+}
+
+
+static void
ngx_http_close_connection(ngx_connection_t *c)
{
ngx_pool_t *pool;
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 636839805..2486ca5c0 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -464,6 +464,7 @@ struct ngx_http_request_s {
unsigned expect_tested:1;
unsigned root_tested:1;
unsigned done:1;
+ unsigned logged:1;
unsigned utf8:1;
unsigned buffered:4;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 6bbf872c1..9144913be 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -22,6 +22,10 @@ static void ngx_http_upstream_send_request(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_request_handler(ngx_event_t *wev);
static void ngx_http_upstream_process_header(ngx_event_t *rev);
+static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
+static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
static void ngx_http_upstream_process_body_in_memory(ngx_event_t *rev);
static void ngx_http_upstream_send_response(ngx_http_request_t *r,
@@ -282,6 +286,15 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = {
};
+static ngx_http_upstream_next_t ngx_http_upstream_next_errors[] = {
+ { 500, NGX_HTTP_UPSTREAM_FT_HTTP_500 },
+ { 502, NGX_HTTP_UPSTREAM_FT_HTTP_502 },
+ { 503, NGX_HTTP_UPSTREAM_FT_HTTP_503 },
+ { 504, NGX_HTTP_UPSTREAM_FT_HTTP_504 },
+ { 404, NGX_HTTP_UPSTREAM_FT_HTTP_404 },
+ { 0, 0 }
+};
+
void
ngx_http_upstream_init(ngx_http_request_t *r)
{
@@ -1047,8 +1060,6 @@ ngx_http_upstream_process_header(ngx_event_t *rev)
ngx_connection_t *c;
ngx_http_request_t *r;
ngx_http_upstream_t *u;
- ngx_http_err_page_t *err_page;
- ngx_http_core_loc_conf_t *clcf;
ngx_http_upstream_header_t *hh;
ngx_http_upstream_main_conf_t *umcf;
@@ -1174,85 +1185,21 @@ ngx_http_upstream_process_header(ngx_event_t *rev)
/* rc == NGX_OK */
- if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST
- && r->subrequest_in_memory)
- {
- u->buffer.last = u->buffer.pos;
- }
-
- if (u->headers_in.status_n == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+ if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST) {
- if (u->peer.tries > 1
- && (u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_500))
- {
- ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_500);
- return;
- }
-
-#if (NGX_HTTP_CACHE)
-
- if (u->peer.tries == 0
- && u->stale
- && (u->conf->use_stale & NGX_HTTP_UPSTREAM_FT_HTTP_500))
- {
- ngx_http_upstream_finalize_request(r, u,
- ngx_http_send_cached_response(r));
- return;
+ if (r->subrequest_in_memory) {
+ u->buffer.last = u->buffer.pos;
}
-#endif
- }
-
- if (u->headers_in.status_n == NGX_HTTP_NOT_FOUND) {
-
- if (u->peer.tries > 1
- && u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_404)
- {
- ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_404);
+ if (ngx_http_upstream_test_next(r, u) == NGX_OK) {
return;
}
- if (u->conf->intercept_404) {
- ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
+ if (ngx_http_upstream_intercept_errors(r, u) == NGX_OK) {
return;
}
}
-
- if (u->headers_in.status_n >= NGX_HTTP_BAD_REQUEST
- && u->conf->intercept_errors)
- {
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
- if (clcf->error_pages) {
-
- err_page = clcf->error_pages->elts;
- for (i = 0; i < clcf->error_pages->nelts; i++) {
- if (err_page[i].status == (ngx_int_t) u->headers_in.status_n) {
-
- if (u->headers_in.status_n == NGX_HTTP_UNAUTHORIZED) {
-
- r->headers_out.www_authenticate =
- ngx_list_push(&r->headers_out.headers);
-
- if (r->headers_out.www_authenticate == NULL) {
- ngx_http_upstream_finalize_request(r, u,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
- return;
- }
-
- *r->headers_out.www_authenticate =
- *u->headers_in.www_authenticate;
- }
-
- ngx_http_upstream_finalize_request(r, u,
- u->headers_in.status_n);
- return;
- }
- }
- }
- }
-
umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
if (u->headers_in.x_accel_redirect) {
@@ -1407,6 +1354,101 @@ ngx_http_upstream_process_header(ngx_event_t *rev)
static ngx_int_t
+ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+ ngx_uint_t status;
+ ngx_http_upstream_next_t *un;
+
+ if (!(u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_STATUS)) {
+ return NGX_DECLINED;
+ }
+
+ status = u->headers_in.status_n;
+
+ for (un = ngx_http_upstream_next_errors; un->status; un++) {
+
+ if (status != un->status) {
+ continue;
+ }
+
+ if (u->peer.tries > 1 && (u->conf->next_upstream & un->mask)) {
+ ngx_http_upstream_next(r, u, un->mask);
+ return NGX_OK;
+ }
+
+ if (status == NGX_HTTP_NOT_FOUND && u->conf->intercept_404) {
+ ngx_http_upstream_finalize_request(r, u, NGX_HTTP_NOT_FOUND);
+ return NGX_OK;
+ }
+
+#if (NGX_HTTP_CACHE)
+
+ if (u->peer.tries == 0 && u->stale && (u->conf->use_stale & un->mask)) {
+ ngx_http_upstream_finalize_request(r, u,
+ ngx_http_send_cached_response(r));
+ return NGX_OK;
+ }
+
+#endif
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
+ ngx_http_upstream_t *u)
+{
+ ngx_int_t status;
+ ngx_uint_t i;
+ ngx_table_elt_t *h;
+ ngx_http_err_page_t *err_page;
+ ngx_http_core_loc_conf_t *clcf;
+
+ if (!u->conf->intercept_errors) {
+ return NGX_DECLINED;
+ }
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->error_pages == NULL) {
+ return NGX_DECLINED;
+ }
+
+ status = u->headers_in.status_n;
+
+ err_page = clcf->error_pages->elts;
+ for (i = 0; i < clcf->error_pages->nelts; i++) {
+
+ if (err_page[i].status == status) {
+
+ if (status == NGX_HTTP_UNAUTHORIZED) {
+
+ h = ngx_list_push(&r->headers_out.headers);
+
+ if (h == NULL) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_OK;
+ }
+
+ *h = *u->headers_in.www_authenticate;
+
+ r->headers_out.www_authenticate = h;
+ }
+
+ ngx_http_upstream_finalize_request(r, u, status);
+
+ return NGX_OK;
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static ngx_int_t
ngx_http_upstream_test_connect(ngx_connection_t *c)
{
int err;
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 66c2cf3da..dd72ba86d 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -20,13 +20,20 @@
#define NGX_HTTP_UPSTREAM_FT_TIMEOUT 0x00000004
#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 0x00000008
#define NGX_HTTP_UPSTREAM_FT_HTTP_500 0x00000010
-#define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000020
-#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_HTTP_502 0x00000020
+#define NGX_HTTP_UPSTREAM_FT_HTTP_503 0x00000040
+#define NGX_HTTP_UPSTREAM_FT_HTTP_504 0x00000080
+#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x00000100
+#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x00000200
+#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x00000400
#define NGX_HTTP_UPSTREAM_FT_NOLIVE 0x40000000
#define NGX_HTTP_UPSTREAM_FT_OFF 0x80000000
+#define NGX_HTTP_UPSTREAM_FT_STATUS (NGX_HTTP_UPSTREAM_FT_HTTP_500 \
+ |NGX_HTTP_UPSTREAM_FT_HTTP_502 \
+ |NGX_HTTP_UPSTREAM_FT_HTTP_503 \
+ |NGX_HTTP_UPSTREAM_FT_HTTP_504 \
+ |NGX_HTTP_UPSTREAM_FT_HTTP_404)
#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40
@@ -267,6 +274,12 @@ struct ngx_http_upstream_s {
};
+typedef struct {
+ ngx_uint_t status;
+ ngx_uint_t mask;
+} ngx_http_upstream_next_t;
+
+
ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 08343b8e8..003510a6a 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -46,6 +46,8 @@ static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_realpath_root(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_server_name(ngx_http_request_t *r,
@@ -162,6 +164,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("document_root"), NULL,
ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+ { ngx_string("realpath_root"), NULL,
+ ngx_http_variable_realpath_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
+
{ ngx_string("query_string"), NULL, ngx_http_variable_request,
offsetof(ngx_http_request_t, args),
NGX_HTTP_VAR_NOCACHEABLE, 0 },
@@ -1000,6 +1005,61 @@ ngx_http_variable_document_root(ngx_http_request_t *r,
static ngx_int_t
+ngx_http_variable_realpath_root(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ size_t len;
+ ngx_str_t path;
+ ngx_http_core_loc_conf_t *clcf;
+ u_char real[NGX_MAX_PATH];
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->root_lengths == NULL) {
+ path = clcf->root;
+
+ } else {
+ if (ngx_http_script_run(r, &path, clcf->root_lengths->elts, 1,
+ clcf->root_values->elts)
+ == NULL)
+ {
+ return NGX_ERROR;
+ }
+
+ path.data[path.len - 1] = '\0';
+
+ if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0)
+ == NGX_ERROR)
+ {
+ return NGX_ERROR;
+ }
+ }
+
+ if (ngx_realpath(path.data, real) == NULL) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_realpath_n " \"%s\" failed", path.data);
+ return NGX_ERROR;
+ }
+
+ len = ngx_strlen(real);
+
+ v->data = ngx_pnalloc(r->pool, len);
+ if (v->data == NULL) {
+ return NGX_ERROR;
+ }
+
+ v->len = len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ ngx_memcpy(v->data, real, len);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_variable_request_filename(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index d7a38d95a..d8182b4b6 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -145,6 +145,8 @@ ngx_int_t ngx_set_file_time(u_char *name, ngx_fd_t fd, time_t s);
#endif
+#define ngx_realpath(p, r) realpath((char *) p, (char *) r)
+#define ngx_realpath_n "realpath()"
#define ngx_getcwd(buf, size) (getcwd(buf, size) != NULL)
#define ngx_getcwd_n "getcwd()"
#define NGX_MAX_PATH PATH_MAX