changeset 572:ff463db0be31 NGINX_0_8_38

nginx 0.8.38 *) Feature: the "proxy_no_cache" and "fastcgi_no_cache" directives. *) Feature: now the "rewrite" directive does a redirect automatically if the $scheme variable is used. Thanks to Piotr Sikora. *) Bugfix: now "limit_req" delay directive conforms to the described algorithm. Thanks to Maxim Dounin. *) Bugfix: the $uid_got variable might not be used in the SSI and perl modules.
author Igor Sysoev <http://sysoev.ru>
date Mon, 24 May 2010 00:00:00 +0400
parents 5b59e716792b
children 7cbc7affef15
files CHANGES CHANGES.ru src/core/nginx.h src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_gzip_static_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_limit_req_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_random_index_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_static_module.c src/http/modules/ngx_http_userid_filter_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_cache.h src/http/ngx_http_core_module.c src/http/ngx_http_file_cache.c src/http/ngx_http_parse.c src/http/ngx_http_request.h src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h
diffstat 26 files changed, 161 insertions(+), 226 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,20 @@
 
+Changes with nginx 0.8.38                                        24 May 2010
+
+    *) Feature: the "proxy_no_cache" and "fastcgi_no_cache" directives.
+
+    *) Feature: now the "rewrite" directive does a redirect automatically 
+       if the $scheme variable is used.
+       Thanks to Piotr Sikora.
+
+    *) Bugfix: now "limit_req" delay directive conforms to the described 
+       algorithm.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the $uid_got variable might not be used in the SSI and perl 
+       modules.
+
+
 Changes with nginx 0.8.37                                        17 May 2010
 
     *) Feature: the ngx_http_split_clients_module.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,20 @@
 
+Изменения в nginx 0.8.38                                          24.05.2010
+
+    *) Добавление: директивы proxy_no_cache и fastcgi_no_cache.
+
+    *) Добавление: теперь при использовании переменной $scheme в директиве 
+       rewrite автоматически делается редирект.
+       Спасибо Piotr Sikora.
+
+    *) Исправление: теперь задержки в директиве limit_req соответствует 
+       описанному алгоритму.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: переменную $uid_got нельзя было использовать в SSI и 
+       перловом модулях.
+
+
 Изменения в nginx 0.8.37                                          17.05.2010
 
     *) Добавление: модуль ngx_http_split_clients_module.
@@ -406,7 +422,7 @@
 
     *) Добавление: директивы limit_req_log_level и limit_conn_log_level.
 
-    *) Исправление: Теперь директива limit_req соответствует алгоритму 
+    *) Исправление: теперь директива limit_req соответствует алгоритму 
        leaky bucket.
        Спасибо Максиму Дунину.
 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8037
-#define NGINX_VERSION      "0.8.37"
+#define nginx_version         8038
+#define NGINX_VERSION      "0.8.38"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -160,10 +160,6 @@ ngx_http_autoindex_handler(ngx_http_requ
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
         return NGX_DECLINED;
     }
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -146,10 +146,6 @@ ngx_http_dav_handler(ngx_http_request_t 
     ngx_int_t                 rc;
     ngx_http_dav_loc_conf_t  *dlcf;
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
 
     if (!(r->method & dlcf->methods)) {
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -162,11 +162,6 @@ static char *ngx_http_fastcgi_cache_key(
 static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post,
     void *data);
 
-static char *ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-static char *ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-
 
 static ngx_conf_post_t  ngx_http_fastcgi_lowat_post =
     { ngx_http_fastcgi_lowat_check };
@@ -341,6 +336,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       0,
       &ngx_http_fastcgi_module },
 
+    { ngx_string("fastcgi_no_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_no_cache_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, upstream.no_cache),
+      NULL },
+
     { ngx_string("fastcgi_cache_valid"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_file_cache_valid_set_slot,
@@ -399,20 +401,6 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream),
       &ngx_http_fastcgi_next_upstream_masks },
 
-    { ngx_string("fastcgi_upstream_max_fails"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_fastcgi_upstream_max_fails_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("fastcgi_upstream_fail_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_fastcgi_upstream_fail_timeout_unsupported,
-      0,
-      0,
-      NULL },
-
     { ngx_string("fastcgi_param"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
       ngx_conf_set_keyval_slot,
@@ -1942,6 +1930,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
 #endif
 
@@ -2163,6 +2152,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
     conf->upstream.cache_methods |= NGX_HTTP_GET|NGX_HTTP_HEAD;
 
+    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+                             prev->upstream.no_cache, NULL);
+
     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                              prev->upstream.cache_valid, NULL);
 
@@ -2749,29 +2741,3 @@ ngx_http_fastcgi_lowat_check(ngx_conf_t 
 
     return NGX_CONF_OK;
 }
-
-
-static char *
-ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"fastcgi_upstream_max_fails\" is not supported, "
-         "use the \"max_fails\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"fastcgi_upstream_fail_timeout\" is not supported, "
-         "use the \"fail_timeout\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -80,10 +80,6 @@ ngx_http_flv_handler(ngx_http_request_t 
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     rc = ngx_http_discard_request_body(r);
 
     if (rc != NGX_OK) {
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -89,10 +89,6 @@ ngx_http_gzip_static_handler(ngx_http_re
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
 
     if (!gzcf->enable) {
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -116,10 +116,6 @@ ngx_http_index_handler(ngx_http_request_
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
--- a/src/http/modules/ngx_http_limit_req_module.c
+++ b/src/http/modules/ngx_http_limit_req_module.c
@@ -229,7 +229,8 @@ ngx_http_limit_req_handler(ngx_http_requ
 
         r->read_event_handler = ngx_http_test_reading;
         r->write_event_handler = ngx_http_limit_req_delay;
-        ngx_add_timer(r->connection->write, (ngx_msec_t) excess);
+        ngx_add_timer(r->connection->write,
+                      (ngx_msec_t) excess * 1000 / ctx->rate);
 
         return NGX_AGAIN;
     }
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -38,11 +38,6 @@ static char *ngx_http_memcached_merge_lo
 static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
-static char *ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-static char *ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-
 
 static ngx_conf_bitmask_t  ngx_http_memcached_next_upstream_masks[] = {
     { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR },
@@ -105,20 +100,6 @@ static ngx_command_t  ngx_http_memcached
       offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream),
       &ngx_http_memcached_next_upstream_masks },
 
-    { ngx_string("memcached_upstream_max_fails"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_memcached_upstream_max_fails_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("memcached_upstream_fail_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_memcached_upstream_fail_timeout_unsupported,
-      0,
-      0,
-      NULL },
-
       ngx_null_command
 };
 
@@ -640,29 +621,3 @@ ngx_http_memcached_pass(ngx_conf_t *cf, 
 
     return NGX_CONF_OK;
 }
-
-
-static char *
-ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"memcached_upstream_max_fails\" is not supported, "
-         "use the \"max_fails\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"memcached_upstream_fail_timeout\" is not supported, "
-         "use the \"fail_timeout\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -142,11 +142,6 @@ static char *ngx_http_proxy_cache_key(ng
 
 static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
 
-static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf);
-
 #if (NGX_HTTP_SSL)
 static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
     ngx_http_proxy_loc_conf_t *plcf);
@@ -364,6 +359,13 @@ static ngx_command_t  ngx_http_proxy_com
       0,
       &ngx_http_proxy_module },
 
+    { ngx_string("proxy_no_cache"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+      ngx_http_no_cache_set_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_proxy_loc_conf_t, upstream.no_cache),
+      NULL },
+
     { ngx_string("proxy_cache_valid"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_file_cache_valid_set_slot,
@@ -422,20 +424,6 @@ static ngx_command_t  ngx_http_proxy_com
       offsetof(ngx_http_proxy_loc_conf_t, upstream.next_upstream),
       &ngx_http_proxy_next_upstream_masks },
 
-    { ngx_string("proxy_upstream_max_fails"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_upstream_max_fails_unsupported,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("proxy_upstream_fail_timeout"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-      ngx_http_proxy_upstream_fail_timeout_unsupported,
-      0,
-      0,
-      NULL },
-
     { ngx_string("proxy_pass_header"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_str_array_slot,
@@ -1936,6 +1924,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_
 #if (NGX_HTTP_CACHE)
     conf->upstream.cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+    conf->upstream.no_cache = NGX_CONF_UNSET_PTR;
     conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
 #endif
 
@@ -2160,6 +2149,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
                                          |NGX_HTTP_UPSTREAM_FT_OFF;
     }
 
+    ngx_conf_merge_ptr_value(conf->upstream.no_cache,
+                             prev->upstream.no_cache, NULL);
+
     ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
                              prev->upstream.cache_valid, NULL);
 
@@ -2959,32 +2951,6 @@ ngx_http_proxy_lowat_check(ngx_conf_t *c
 }
 
 
-static char *
-ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"proxy_upstream_max_fails\" is not supported, "
-         "use the \"max_fails\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
-    ngx_command_t *cmd, void *conf)
-{
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-         "\"proxy_upstream_fail_timeout\" is not supported, "
-         "use the \"fail_timeout\" parameter of the \"server\" directive ",
-         "inside the \"upstream\" block");
-
-    return NGX_CONF_ERROR;
-}
-
-
 #if (NGX_HTTP_SSL)
 
 static ngx_int_t
--- a/src/http/modules/ngx_http_random_index_module.c
+++ b/src/http/modules/ngx_http_random_index_module.c
@@ -86,10 +86,6 @@ ngx_http_random_index_handler(ngx_http_r
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
         return NGX_DECLINED;
     }
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -341,13 +341,10 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
 
     last = 0;
 
-    if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) {
-        regex->status = NGX_HTTP_MOVED_TEMPORARILY;
-        regex->redirect = 1;
-        last = 1;
-    }
-
-    if (ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0) {
+    if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0
+        || ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0
+        || ngx_strncmp(value[2].data, "$scheme", sizeof("$scheme") - 1) == 0)
+    {
         regex->status = NGX_HTTP_MOVED_TEMPORARILY;
         regex->redirect = 1;
         last = 1;
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -66,10 +66,6 @@ ngx_http_static_handler(ngx_http_request
         return NGX_DECLINED;
     }
 
-    if (r->zero_in_uri) {
-        return NGX_DECLINED;
-    }
-
     log = r->connection->log;
 
     /*
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -543,7 +543,7 @@ ngx_http_userid_add_variables(ngx_conf_t
 {
     ngx_http_variable_t  *var;
 
-    var = ngx_http_add_variable(cf, &ngx_http_userid_got, NGX_HTTP_VAR_NOHASH);
+    var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
     if (var == NULL) {
         return NGX_ERROR;
     }
--- 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.8.37';
+our $VERSION = '0.8.38';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -168,10 +168,6 @@ ngx_http_perl_xs_init(pTHX)
 static ngx_int_t
 ngx_http_perl_handler(ngx_http_request_t *r)
 {
-    if (r->zero_in_uri) {
-        return NGX_HTTP_NOT_FOUND;
-    }
-
     r->main->count++;
 
     ngx_http_perl_handle_request(r);
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -134,6 +134,11 @@ char *ngx_http_file_cache_set_slot(ngx_c
 char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
+ngx_int_t ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache);
+char *ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+
+
 extern ngx_str_t  ngx_http_cache_status[];
 
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1341,7 +1341,7 @@ ngx_http_core_content_phase(ngx_http_req
 
     /* no content handler was found */
 
-    if (r->uri.data[r->uri.len - 1] == '/' && !r->zero_in_uri) {
+    if (r->uri.data[r->uri.len - 1] == '/') {
 
         if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -2104,7 +2104,6 @@ ngx_http_subrequest(ngx_http_request_t *
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
                    "http subrequest \"%V?%V\"", uri, &sr->args);
 
-    sr->zero_in_uri = (flags & NGX_HTTP_ZERO_IN_URI) != 0;
     sr->subrequest_in_memory = (flags & NGX_HTTP_SUBREQUEST_IN_MEMORY) != 0;
     sr->waited = (flags & NGX_HTTP_SUBREQUEST_WAITED) != 0;
 
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1692,3 +1692,69 @@ ngx_http_file_cache_valid_set_slot(ngx_c
 
     return NGX_CONF_OK;
 }
+
+
+ngx_int_t
+ngx_http_cache(ngx_http_request_t *r, ngx_array_t *no_cache)
+{
+    ngx_str_t                  val;
+    ngx_uint_t                 i;
+    ngx_http_complex_value_t  *cv;
+
+    cv = no_cache->elts;
+
+    for (i = 0; i < no_cache->nelts; i++) {
+        if (ngx_http_complex_value(r, &cv[i], &val) != NGX_OK) {
+            return NGX_ERROR;
+        }
+
+        if (val.len && val.data[0] != '0') {
+            return NGX_DECLINED;
+        }
+    }
+
+    return NGX_OK;
+}
+
+
+char *
+ngx_http_no_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_str_t                          *value;
+    ngx_uint_t                          i;
+    ngx_array_t                       **a;
+    ngx_http_complex_value_t           *cv;
+    ngx_http_compile_complex_value_t    ccv;
+
+    a = (ngx_array_t **) (p + cmd->offset);
+
+    if (*a == NGX_CONF_UNSET_PTR) {
+        *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_complex_value_t));
+        if (*a == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    value = cf->args->elts;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+        cv = ngx_array_push(*a);
+        if (cv == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+        ccv.cf = cf;
+        ccv.value = &value[i];
+        ccv.complex_value = cv;
+
+        if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    return NGX_CONF_OK;
+}
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -438,8 +438,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->plus_in_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             default:
                 state = sw_check_uri;
                 break;
@@ -496,8 +495,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->plus_in_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
@@ -526,8 +524,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->complex_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
@@ -1202,7 +1199,7 @@ ngx_http_parse_complex_uri(ngx_http_requ
                     ch = *p++;
 
                 } else if (ch == '\0') {
-                    r->zero_in_uri = 1;
+                    return NGX_HTTP_PARSE_INVALID_REQUEST;
                 }
 
                 state = quoted_state;
@@ -1304,8 +1301,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
         }
 
         if (ch == '\0') {
-            *flags |= NGX_HTTP_ZERO_IN_URI;
-            continue;
+            goto unsafe;
         }
 
         if (ngx_path_separator(ch) && len > 2) {
@@ -1449,34 +1445,19 @@ ngx_http_arg(ngx_http_request_t *r, u_ch
 void
 ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
 {
-    u_char  ch, *p, *last;
-
-    p = uri->data;
-
-    last = p + uri->len;
+    u_char  *p, *last;
 
-    args->len = 0;
+    last = uri->data + uri->len;
 
-    while (p < last) {
-
-        ch = *p++;
+    p = ngx_strlchr(uri->data, last, '?');
 
-        if (ch == '?') {
-            args->len = last - p;
-            args->data = p;
-
-            uri->len = p - 1 - uri->data;
+    if (p) {
+        uri->len = p - uri->data;
+        p++;
+        args->len = last - p;
+        args->data = p;
 
-            if (ngx_strlchr(p, last, '\0') != NULL) {
-                r->zero_in_uri = 1;
-            }
-
-            return;
-        }
-
-        if (ch == '\0') {
-            r->zero_in_uri = 1;
-            continue;
-        }
+    } else {
+        args->len = 0;
     }
 }
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -56,7 +56,7 @@
 #define NGX_HTTP_PARSE_INVALID_HEADER      13
 
 
-#define NGX_HTTP_ZERO_IN_URI               1
+/* unused                                  1 */
 #define NGX_HTTP_SUBREQUEST_IN_MEMORY      2
 #define NGX_HTTP_SUBREQUEST_WAITED         4
 #define NGX_HTTP_LOG_UNSAFE                8
@@ -435,9 +435,6 @@ struct ngx_http_request_s {
     /* URI with "+" */
     unsigned                          plus_in_uri:1;
 
-    /* URI with "\0" or "%00" */
-    unsigned                          zero_in_uri:1;
-
     unsigned                          invalid_header:1;
 
     unsigned                          valid_location:1;
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -517,8 +517,6 @@ ngx_http_send_error_page(ngx_http_reques
 
     r->err_status = overwrite;
 
-    r->zero_in_uri = 0;
-
     if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) {
         return NGX_ERROR;
     }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -621,6 +621,13 @@ ngx_http_upstream_cache(ngx_http_request
 
     if (c == NULL) {
 
+        if (u->conf->no_cache) {
+            rc = ngx_http_cache(r, u->conf->no_cache);
+            if (rc != NGX_OK) {
+                return rc;
+            }
+        }
+
         if (!(r->method & u->conf->cache_methods)) {
             return NGX_DECLINED;
         }
@@ -1808,10 +1815,6 @@ ngx_http_upstream_process_headers(ngx_ht
             return NGX_DONE;
         }
 
-        if (flags & NGX_HTTP_ZERO_IN_URI) {
-            r->zero_in_uri = 1;
-        }
-
         if (r->method != NGX_HTTP_HEAD) {
             r->method = NGX_HTTP_GET;
         }
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -162,6 +162,7 @@ typedef struct {
     ngx_uint_t                       cache_methods;
 
     ngx_array_t                     *cache_valid;
+    ngx_array_t                     *no_cache; /* ngx_http_complex_value_t */
 #endif
 
     ngx_array_t                     *store_lengths;