changeset 478:f2c6a7373274 NGINX_0_7_51

nginx 0.7.51 *) Feature: the "try_files" directive supports a response code in the fallback parameter. *) Feature: now any response code can be used in the "return" directive. *) Bugfix: the "error_page" directive made an external redirect without query string; the bug had appeared in 0.7.44. *) Bugfix: if servers listened on several defined explicitly addresses, then virtual servers might not work; the bug had appeared in 0.7.39.
author Igor Sysoev <http://sysoev.ru>
date Sun, 12 Apr 2009 00:00:00 +0400
parents ba2ea8c4d60f
children eb4fdebda673
files CHANGES CHANGES.ru conf/nginx.conf src/core/nginx.h src/core/ngx_cycle.c src/http/modules/perl/nginx.pm src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_file_cache.c src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/os/unix/ngx_files.h
diffstat 16 files changed, 196 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,13 +1,27 @@
 
+Changes with nginx 0.7.51                                        12 Apr 2009
+
+    *) Feature: the "try_files" directive supports a response code in the 
+       fallback parameter.
+
+    *) Feature: now any response code can be used in the "return" directive.
+
+    *) Bugfix: the "error_page" directive made an external redirect without 
+       query string; the bug had appeared in 0.7.44.
+
+    *) Bugfix: if servers listened on several defined explicitly addresses, 
+       then virtual servers might not work; the bug had appeared in 0.7.39.
+
+
 Changes with nginx 0.7.50                                        06 Apr 2009
 
-    *) Change: a segmentation fault might occur in worker process, if the 
-       $arg_... variables were used; the bug had appeared in 0.7.48.
+    *) Bugfix: the $arg_... variables did not work; the bug had appeared in 
+       0.7.49.
 
 
 Changes with nginx 0.7.49                                        06 Apr 2009
 
-    *) Change: a segmentation fault might occur in worker process, if the 
+    *) Bugfix: a segmentation fault might occur in worker process, if the 
        $arg_... variables were used; the bug had appeared in 0.7.48.
 
 
@@ -213,7 +227,7 @@ Changes with nginx 0.7.35               
        original request extension.
 
     *) Bugfix: "*domain.tld" names were handled incorrectly in 
-       "server_name", "valid_referers", and "map" directives, if an 
+       "server_name", "valid_referers", and "map" directives, if 
        ".domain.tld" and ".subdomain.domain.tld" wildcards were used; 
        the bug had appeared in 0.7.9.
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,14 +1,30 @@
 
+Изменения в nginx 0.7.51                                          12.04.2009
+
+    *) Добавление: директива try_files поддерживает код ответа в последнем 
+       параметре.
+
+    *) Добавление: теперь в директиве return можно использовать любой код 
+       ответа.
+
+    *) Исправление: директива error_page делала внешний редирект без строки 
+       запроса; ошибка появилась в 0.7.44.
+
+    *) Исправление: если сервера слушали на нескольких явно описанных 
+       адресах, то виртуальные сервера могли не работать; ошибка появилась 
+       в 0.7.39.
+
+
 Изменения в nginx 0.7.50                                          06.04.2009
 
-    *) Изменение: при использовании переменных $arg_... в рабочем процессе 
-       мог произойти segmentation fault; ошибка появилась в 0.7.48.
+    *) Исправление: переменные $arg_... не работали; ошибка появилась в 
+       0.7.49.
 
 
 Изменения в nginx 0.7.49                                          06.04.2009
 
-    *) Изменение: при использовании переменных $arg_... в рабочем процессе 
-       мог произойти segmentation fault; ошибка появилась в 0.7.48.
+    *) Исправление: при использовании переменных $arg_... в рабочем 
+       процессе мог произойти segmentation fault; ошибка появилась в 0.7.48.
 
 
 Изменения в nginx 0.7.48                                          06.04.2009
--- a/conf/nginx.conf
+++ b/conf/nginx.conf
@@ -19,7 +19,7 @@ http {
     default_type  application/octet-stream;
 
     #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
-    #                  '"$status" $body_bytes_sent "$http_referer" '
+    #                  '$status $body_bytes_sent "$http_referer" '
     #                  '"$http_user_agent" "$http_x_forwarded_for"';
 
     #access_log  logs/access.log  main;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version       007050
-#define NGINX_VERSION      "0.7.50"
+#define nginx_version       007051
+#define NGINX_VERSION      "0.7.51"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -375,14 +375,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             goto failed;
         }
 
-#if (NGX_WIN32)
-        if (ngx_file_append_mode(file[i].fd) != NGX_OK) {
-            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
-                          ngx_file_append_mode_n " \"%s\" failed",
-                          file[i].name.data);
-            goto failed;
-        }
-#else
+#if !(NGX_WIN32)
         if (fcntl(file[i].fd, F_SETFD, FD_CLOEXEC) == -1) {
             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                           "fcntl(FD_CLOEXEC) \"%s\" failed",
@@ -929,21 +922,20 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s
 ngx_int_t
 ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log)
 {
-    size_t            len;
-    ngx_uint_t        trunc;
-    ngx_file_t        file;
-    u_char            pid[NGX_INT64_LEN + 2];
+    size_t      len;
+    ngx_uint_t  create;
+    ngx_file_t  file;
+    u_char      pid[NGX_INT64_LEN + 2];
 
     ngx_memzero(&file, sizeof(ngx_file_t));
 
     file.name = *name;
     file.log = log;
 
-    trunc = ngx_test_config ? 0 : NGX_FILE_TRUNCATE;
+    create = ngx_test_config ? NGX_FILE_CREATE_OR_OPEN : NGX_FILE_TRUNCATE;
 
     file.fd = ngx_open_file(file.name.data, NGX_FILE_RDWR,
-                            NGX_FILE_CREATE_OR_OPEN|trunc,
-                            NGX_FILE_DEFAULT_ACCESS);
+                            create, NGX_FILE_DEFAULT_ACCESS);
 
     if (file.fd == NGX_INVALID_FILE) {
         ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
@@ -1078,21 +1070,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx
             continue;
         }
 
-#if (NGX_WIN32)
-        if (ngx_file_append_mode(fd) == NGX_ERROR) {
-            ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
-                          ngx_file_append_mode_n " \"%s\" failed",
-                          file[i].name.data);
-
-            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed",
-                              file[i].name.data);
-            }
-
-            continue;
-        }
-#else
+#if !(NGX_WIN32)
         if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) {
             ngx_file_info_t  fi;
 
--- 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.50';
+our $VERSION = '0.7.51';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1373,10 +1373,10 @@ static ngx_int_t
 ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_array_t *ports)
 {
-    ngx_uint_t                s, p, a;
-    ngx_http_conf_port_t     *port;
-    ngx_http_conf_addr_t     *addr;
-    ngx_http_server_name_t   *name;
+    ngx_uint_t               s, p, a;
+    ngx_http_conf_port_t    *port;
+    ngx_http_conf_addr_t    *addr;
+    ngx_http_server_name_t  *name;
 
     port = ports->elts;
     for (p = 0; p < ports->nelts; p++) {
@@ -1425,13 +1425,13 @@ static ngx_int_t
 ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
     ngx_http_conf_addr_t *addr)
 {
-    ngx_int_t                  rc;
-    ngx_uint_t                 s;
-    ngx_hash_init_t            hash;
-    ngx_http_server_name_t    *name;
-    ngx_hash_keys_arrays_t     ha;
+    ngx_int_t                rc;
+    ngx_uint_t               s;
+    ngx_hash_init_t          hash;
+    ngx_hash_keys_arrays_t   ha;
+    ngx_http_server_name_t  *name;
 #if (NGX_PCRE)
-    ngx_uint_t                 regex, i;
+    ngx_uint_t               regex, i;
 
     regex = 0;
 #endif
@@ -1825,7 +1825,7 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_h
             return NGX_ERROR;
         }
 
-        addrs[i].conf.core_srv_conf->virtual_names = vn;
+        addrs[i].conf.virtual_names = vn;
 
         vn->names.hash = addr[i].hash;
         vn->names.wc_head = addr[i].wc_head;
@@ -1882,7 +1882,7 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_
             return NGX_ERROR;
         }
 
-        addrs6[i].conf.core_srv_conf->virtual_names = vn;
+        addrs6[i].conf.virtual_names = vn;
 
         vn->names.hash = addr[i].hash;
         vn->names.wc_head = addr[i].wc_head;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1144,6 +1144,11 @@ ngx_http_core_try_files_phase(ngx_http_r
 
         if (tf->lengths == NULL && tf->name.len == 0) {
 
+            if (tf->code) {
+                ngx_http_finalize_request(r, tf->code);
+                return NGX_OK;
+            }
+
             path.len -= root;
             path.data += root;
 
@@ -3875,7 +3880,7 @@ ngx_http_core_error_page(ngx_conf_t *cf,
     args.len = 0;
     args.data = NULL;
 
-    if (cv.lengths == NULL) {
+    if (cv.lengths == NULL && uri.data[0] == '/') {
         p = (u_char *) ngx_strchr(uri.data, '?');
 
         if (p) {
@@ -3939,6 +3944,7 @@ ngx_http_core_try_files(ngx_conf_t *cf, 
     ngx_http_core_loc_conf_t *clcf = conf;
 
     ngx_str_t                  *value;
+    ngx_int_t                   code;
     ngx_uint_t                  i, n;
     ngx_http_try_file_t        *tf;
     ngx_http_script_compile_t   sc;
@@ -3994,6 +4000,20 @@ ngx_http_core_try_files(ngx_conf_t *cf, 
         }
     }
 
+    if (tf[i - 1].name.data[0] == '=') {
+
+        code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2);
+
+        if (code == NGX_ERROR) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid code \"%*s\"",
+                               tf[i - 1].name.len - 1, tf[i - 1].name.data);
+            return NGX_CONF_ERROR;
+        }
+
+        tf[i].code = code;
+    }
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -153,8 +153,6 @@ typedef struct {
     /* server ctx */
     ngx_http_conf_ctx_t        *ctx;
 
-    ngx_http_virtual_names_t   *virtual_names;
-
     ngx_str_t                   server_name;
 
     size_t                      connection_pool_size;
@@ -180,6 +178,8 @@ typedef struct {
     /* the default server configuration for this address:port */
     ngx_http_core_srv_conf_t  *core_srv_conf;
 
+    ngx_http_virtual_names_t  *virtual_names;
+
 #if (NGX_HTTP_SSL)
     ngx_uint_t                 ssl;   /* unsigned  ssl:1; */
 #endif
@@ -267,7 +267,9 @@ typedef struct {
     ngx_array_t               *lengths;
     ngx_array_t               *values;
     ngx_str_t                  name;
-    ngx_uint_t                 test_dir;   /* unsigned  test_dir:1; */
+
+    unsigned                   code:10;
+    unsigned                   test_dir:1;
 } ngx_http_try_file_t;
 
 
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -417,7 +417,7 @@ ngx_http_file_cache_exists(ngx_http_file
     if (fcn == NULL) {
         ngx_shmtx_unlock(&cache->shpool->mutex);
 
-        ngx_http_file_cache_forced_expire(cache);
+        (void) ngx_http_file_cache_forced_expire(cache);
 
         ngx_shmtx_lock(&cache->shpool->mutex);
 
@@ -818,12 +818,12 @@ ngx_http_file_cache_forced_expire(ngx_ht
 
     name = ngx_alloc(len + 1, ngx_cycle->log);
     if (name == NULL) {
-        return 60;
+        return 10;
     }
 
     ngx_memcpy(name, path->name.data, path->name.len);
 
-    wait = 60;
+    wait = 10;
     tries = 0;
 
     ngx_shmtx_lock(&cache->shpool->mutex);
@@ -891,7 +891,7 @@ ngx_http_file_cache_expire(ngx_http_file
 
     name = ngx_alloc(len + 1, ngx_cycle->log);
     if (name == NULL) {
-        return 60;
+        return 10;
     }
 
     ngx_memcpy(name, path->name.data, path->name.len);
@@ -903,7 +903,7 @@ ngx_http_file_cache_expire(ngx_http_file
     for ( ;; ) {
 
         if (ngx_queue_empty(cache->queue)) {
-            wait = 60;
+            wait = 10;
             break;
         }
 
@@ -914,7 +914,7 @@ ngx_http_file_cache_expire(ngx_http_file
         wait = fcn->expire - now;
 
         if (wait > 0) {
-            wait = wait > 60 ? 60 : wait;
+            wait = wait > 10 ? 10 : wait;
             break;
         }
 
@@ -1042,7 +1042,7 @@ ngx_http_file_cache_manager(void *data)
         cache->files = 0;
 
         if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) {
-            return 60;
+            return 10;
         }
 
         *cache->cold = 0;
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -61,7 +61,8 @@ static ngx_str_t ngx_http_status_lines[]
 
     /* ngx_null_string, */  /* "207 Multi-Status" */
 
-#define NGX_HTTP_LEVEL_200  7
+#define NGX_HTTP_LAST_LEVEL_200  207
+#define NGX_HTTP_LEVEL_200       (NGX_HTTP_LAST_LEVEL_200 - 200)
 
     /* ngx_null_string, */  /* "300 Multiple Choices" */
 
@@ -74,7 +75,8 @@ static ngx_str_t ngx_http_status_lines[]
     /* ngx_null_string, */  /* "306 unused" */
     /* ngx_null_string, */  /* "307 Temporary Redirect" */
 
-#define NGX_HTTP_LEVEL_300  4
+#define NGX_HTTP_LAST_LEVEL_300  305
+#define NGX_HTTP_LEVEL_300       (NGX_HTTP_LAST_LEVEL_300 - 301)
 
     ngx_string("400 Bad Request"),
     ngx_string("401 Unauthorized"),
@@ -106,7 +108,8 @@ static ngx_str_t ngx_http_status_lines[]
     /* ngx_null_string, */  /* "423 Locked" */
     /* ngx_null_string, */  /* "424 Failed Dependency" */
 
-#define NGX_HTTP_LEVEL_400  17
+#define NGX_HTTP_LAST_LEVEL_400  417
+#define NGX_HTTP_LEVEL_400       (NGX_HTTP_LAST_LEVEL_400 - 400)
 
     ngx_string("500 Internal Server Error"),
     ngx_string("501 Method Not Implemented"),
@@ -120,6 +123,9 @@ static ngx_str_t ngx_http_status_lines[]
     /* ngx_null_string, */  /* "508 unused" */
     /* ngx_null_string, */  /* "509 unused" */
     /* ngx_null_string, */  /* "510 Not Extended" */
+
+#define NGX_HTTP_LAST_LEVEL_500  508
+
 };
 
 
@@ -153,7 +159,7 @@ ngx_http_header_filter(ngx_http_request_
 {
     u_char                    *p;
     size_t                     len;
-    ngx_str_t                  host;
+    ngx_str_t                  host, *status_line;
     ngx_buf_t                 *b;
     ngx_uint_t                 status, i, port;
     ngx_chain_t                out;
@@ -199,17 +205,21 @@ ngx_http_header_filter(ngx_http_request_
 
     if (r->headers_out.status_line.len) {
         len += r->headers_out.status_line.len;
+        status_line = &r->headers_out.status_line;
 #if (NGX_SUPPRESS_WARN)
-        status = NGX_INVALID_ARRAY_INDEX;
+        status = 0;
 #endif
 
     } else {
 
-        if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY) {
+        status = r->headers_out.status;
+
+        if (status >= NGX_HTTP_OK
+            && status < NGX_HTTP_LAST_LEVEL_200)
+        {
             /* 2XX */
-            status = r->headers_out.status - NGX_HTTP_OK;
 
-            if (r->headers_out.status == NGX_HTTP_NO_CONTENT) {
+            if (status == NGX_HTTP_NO_CONTENT) {
                 r->header_only = 1;
                 r->headers_out.content_type.len = 0;
                 r->headers_out.content_type.data = NULL;
@@ -219,30 +229,50 @@ ngx_http_header_filter(ngx_http_request_
                 r->headers_out.content_length_n = -1;
             }
 
-        } else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST) {
+            status -= NGX_HTTP_OK;
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
+
+        } else if (status >= NGX_HTTP_MOVED_PERMANENTLY
+                   && status < NGX_HTTP_LAST_LEVEL_300)
+        {
             /* 3XX */
-            status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY
-                                           + NGX_HTTP_LEVEL_200;
 
-            if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
+            if (status == NGX_HTTP_NOT_MODIFIED) {
                 r->header_only = 1;
             }
 
-        } else if (r->headers_out.status < NGX_HTTP_INTERNAL_SERVER_ERROR) {
+            status = status - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
+
+        } else if (status >= NGX_HTTP_BAD_REQUEST
+                   && status < NGX_HTTP_LAST_LEVEL_400) 
+        {
             /* 4XX */
-            status = r->headers_out.status - NGX_HTTP_BAD_REQUEST
-                                           + NGX_HTTP_LEVEL_200
-                                           + NGX_HTTP_LEVEL_300;
+            status = status - NGX_HTTP_BAD_REQUEST
+                            + NGX_HTTP_LEVEL_200
+                            + NGX_HTTP_LEVEL_300;
+
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
+
+        } else if (status >= NGX_HTTP_INTERNAL_SERVER_ERROR
+                   && status < NGX_HTTP_LAST_LEVEL_500)
+        {
+            /* 5XX */
+            status = status - NGX_HTTP_INTERNAL_SERVER_ERROR
+                            + NGX_HTTP_LEVEL_200
+                            + NGX_HTTP_LEVEL_300
+                            + NGX_HTTP_LEVEL_400;
+
+            status_line = &ngx_http_status_lines[status];
+            len += ngx_http_status_lines[status].len;
 
         } else {
-            /* 5XX */
-            status = r->headers_out.status - NGX_HTTP_INTERNAL_SERVER_ERROR
-                                           + NGX_HTTP_LEVEL_200
-                                           + NGX_HTTP_LEVEL_300
-                                           + NGX_HTTP_LEVEL_400;
+            len += NGX_INT_T_LEN;
+            status_line = NULL;
         }
-
-        len += ngx_http_status_lines[status].len;
     }
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -400,13 +430,11 @@ ngx_http_header_filter(ngx_http_request_
     b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
 
     /* status line */
-    if (r->headers_out.status_line.len) {
-        b->last = ngx_copy(b->last, r->headers_out.status_line.data,
-                           r->headers_out.status_line.len);
+    if (status_line) {
+        b->last = ngx_copy(b->last, status_line->data, status_line->len);
 
     } else {
-        b->last = ngx_copy(b->last, ngx_http_status_lines[status].data,
-                           ngx_http_status_lines[status].len);
+        b->last = ngx_sprintf(b->last, "%ui", status);
     }
     *b->last++ = CR; *b->last++ = LF;
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -372,6 +372,8 @@ ngx_http_init_request(ngx_event_t *rev)
         }
     }
 
+    r->virtual_names = addr_conf->virtual_names;
+
     /* the default server configuration for the address:port */
     cscf = addr_conf->core_srv_conf;
 
@@ -1609,15 +1611,11 @@ ngx_http_find_virtual_server(ngx_http_re
 {
     u_char                    *server;
     ngx_uint_t                 hash;
-    ngx_http_virtual_names_t  *vn;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
     u_char                     buf[32];
 
-    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
-    vn = cscf->virtual_names;
-
-    if (vn == NULL) {
+    if (r->virtual_names == NULL) {
         return NGX_DECLINED;
     }
 
@@ -1633,7 +1631,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
     hash = ngx_hash_strlow(server, host, len);
 
-    cscf = ngx_hash_find_combined(&vn->names, hash, server, len);
+    cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len);
 
     if (cscf) {
         goto found;
@@ -1641,7 +1639,7 @@ ngx_http_find_virtual_server(ngx_http_re
 
 #if (NGX_PCRE)
 
-    if (vn->nregex) {
+    if (r->virtual_names->nregex) {
         size_t                   ncaptures;
         ngx_int_t                n;
         ngx_uint_t               i;
@@ -1653,9 +1651,9 @@ ngx_http_find_virtual_server(ngx_http_re
 
         ncaptures = 0;
 
-        sn = vn->regex;
-
-        for (i = 0; i < vn->nregex; i++) {
+        sn = r->virtual_names->regex;
+
+        for (i = 0; i < r->virtual_names->nregex; i++) {
 
             if (sn[i].captures && r->captures == NULL) {
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -387,6 +387,8 @@ struct ngx_http_request_s {
     ngx_http_post_subrequest_t       *post_subrequest;
     ngx_http_posted_request_t        *posted_requests;
 
+    ngx_http_virtual_names_t         *virtual_names;
+
     ngx_int_t                         phase_handler;
     ngx_http_handler_pt               content_handler;
     ngx_uint_t                        access_code;
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -275,14 +275,16 @@ static ngx_str_t ngx_http_error_pages[] 
 
     ngx_null_string,                     /* 201, 204 */
 
-#define NGX_HTTP_LEVEL_200  1
+#define NGX_HTTP_LAST_LEVEL_200  202
+#define NGX_HTTP_LEVEL_200       (NGX_HTTP_LAST_LEVEL_200 - 201)
 
     /* ngx_null_string, */               /* 300 */
     ngx_string(ngx_http_error_301_page),
     ngx_string(ngx_http_error_302_page),
     ngx_null_string,                     /* 303 */
 
-#define NGX_HTTP_LEVEL_300  3
+#define NGX_HTTP_LAST_LEVEL_300  304
+#define NGX_HTTP_LEVEL_300       (NGX_HTTP_LAST_LEVEL_300 - 301)
 
     ngx_string(ngx_http_error_400_page),
     ngx_string(ngx_http_error_401_page),
@@ -302,7 +304,8 @@ static ngx_str_t ngx_http_error_pages[] 
     ngx_string(ngx_http_error_415_page),
     ngx_string(ngx_http_error_416_page),
 
-#define NGX_HTTP_LEVEL_400  17
+#define NGX_HTTP_LAST_LEVEL_400  417
+#define NGX_HTTP_LEVEL_400       (NGX_HTTP_LAST_LEVEL_400 - 400)
 
     ngx_string(ngx_http_error_495_page), /* 495, https certificate error */
     ngx_string(ngx_http_error_496_page), /* 496, https no certificate */
@@ -318,6 +321,9 @@ static ngx_str_t ngx_http_error_pages[] 
     ngx_null_string,                     /* 505 */
     ngx_null_string,                     /* 506 */
     ngx_string(ngx_http_error_507_page)
+
+#define NGX_HTTP_LAST_LEVEL_500  508
+
 };
 
 
@@ -402,16 +408,22 @@ ngx_http_special_response_handler(ngx_ht
         /* 204 */
         err = 0;
 
-    } else if (error < NGX_HTTP_BAD_REQUEST) {
+    } else if (error >= NGX_HTTP_MOVED_PERMANENTLY
+               && error < NGX_HTTP_LAST_LEVEL_300)
+    {
         /* 3XX */
         err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200;
 
-    } else if (error < NGX_HTTP_OWN_CODES) {
+    } else if (error >= NGX_HTTP_BAD_REQUEST
+               && error < NGX_HTTP_LAST_LEVEL_400)
+    {
         /* 4XX */
         err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200
                                            + NGX_HTTP_LEVEL_300;
 
-    } else {
+    } else if (error >= NGX_HTTP_OWN_CODES
+               && error < NGX_HTTP_LAST_LEVEL_500)
+    {
         /* 49X, 5XX */
         err = error - NGX_HTTP_OWN_CODES + NGX_HTTP_LEVEL_200
                                          + NGX_HTTP_LEVEL_300
@@ -423,6 +435,10 @@ ngx_http_special_response_handler(ngx_ht
                 r->err_status = NGX_HTTP_BAD_REQUEST;
                 break;
         }
+
+    } else {
+        /* unknown code, zero body */
+        err = 0;
     }
 
     return ngx_http_send_special_response(r, clcf, err);
@@ -451,14 +467,14 @@ ngx_http_send_error_page(ngx_http_reques
         return NGX_ERROR;
     }
 
-    if (err_page->value.lengths) {
-        ngx_http_split_args(r, &uri, &args);
+    if (uri.data[0] == '/') {
 
-    } else {
-        args = err_page->args;
-    }
+        if (err_page->value.lengths) {
+            ngx_http_split_args(r, &uri, &args);
 
-    if (uri.data[0] == '/') {
+        } else {
+            args = err_page->args;
+        }
 
         if (r->method != NGX_HTTP_HEAD) {
             r->method = NGX_HTTP_GET;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1945,6 +1945,9 @@ ngx_http_upstream_send_response(ngx_http
         }
     }
 
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "http cacheable: %d", u->cacheable);
+
 #endif
 
     p = u->pipe;
@@ -2746,7 +2749,7 @@ ngx_http_upstream_finalize_request(ngx_h
 
 #if (NGX_HTTP_CACHE)
 
-    if (r->cache) {
+    if (u->cacheable) {
         time_t  valid;
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -2768,7 +2771,8 @@ ngx_http_upstream_finalize_request(ngx_h
 
 #endif
 
-    if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
+    if (u->header_sent
+        && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
     {
         rc = 0;
     }
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -63,7 +63,7 @@ typedef struct {
 #define NGX_FILE_RDWR            O_RDWR
 #define NGX_FILE_CREATE_OR_OPEN  O_CREAT
 #define NGX_FILE_OPEN            0
-#define NGX_FILE_TRUNCATE        O_TRUNC
+#define NGX_FILE_TRUNCATE        O_CREAT|O_TRUNC
 #define NGX_FILE_APPEND          O_WRONLY|O_APPEND
 
 #define NGX_FILE_DEFAULT_ACCESS  0644