changeset 1454:f497ed7682a7

open_file_cache in HTTP
author Igor Sysoev <igor@sysoev.ru>
date Sat, 01 Sep 2007 12:12:48 +0000
parents f2feed5bffe1
children 7f2adaebb81f
files src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.xs src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_script.c
diffstat 7 files changed, 304 insertions(+), 297 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -60,20 +60,17 @@ ngx_module_t  ngx_http_flv_module = {
 static ngx_int_t
 ngx_http_flv_handler(ngx_http_request_t *r)
 {
-    u_char                    *p;
+    u_char                    *p, *last;
     off_t                      start, len;
     size_t                     root;
     ngx_fd_t                   fd;
     ngx_int_t                  rc;
     ngx_uint_t                 level, i;
     ngx_str_t                  path;
-    ngx_err_t                  err;
     ngx_log_t                 *log;
     ngx_buf_t                 *b;
     ngx_chain_t                out[2];
-    ngx_file_info_t            fi;
-    ngx_pool_cleanup_t        *cln;
-    ngx_pool_cleanup_file_t   *clnf;
+    ngx_open_file_info_t       of;
     ngx_http_core_loc_conf_t  *clcf;
 
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
@@ -95,64 +92,65 @@ ngx_http_flv_handler(ngx_http_request_t 
         return rc;
     }
 
-    if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
+    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
+    if (last == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
     log = r->connection->log;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                   "http flv filename: \"%s\"", path.data);
+    path.len = last - path.data;
 
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
-    if (cln == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                   "http flv filename: \"%V\"", &path);
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+    of.test_dir = 0;
+    of.retest = clcf->open_file_cache_retest;
+    of.errors = clcf->open_file_cache_errors;
+    
+    rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
 
-    if (fd == NGX_INVALID_FILE) {
-        err = ngx_errno;
+    if (rc == NGX_ERROR) {
 
-        if (err == NGX_ENOENT
-            || err == NGX_ENOTDIR
-            || err == NGX_ENAMETOOLONG)
-        {
+        switch (of.err) {
+
+        case 0:
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+
+        case NGX_ENOENT:
+        case NGX_ENOTDIR:
+        case NGX_ENAMETOOLONG:
+
             level = NGX_LOG_ERR;
             rc = NGX_HTTP_NOT_FOUND;
+            break;
 
-        } else if (err == NGX_EACCES) {
+        case NGX_EACCES:
+
             level = NGX_LOG_ERR;
             rc = NGX_HTTP_FORBIDDEN;
+            break;
 
-        } else {
+        default:
+
             level = NGX_LOG_CRIT;
             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            break;
         }
 
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
         if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
-            ngx_log_error(level, log, err,
+            ngx_log_error(level, log, of.err,
                           ngx_open_file_n " \"%s\" failed", path.data);
         }
 
         return rc;
     }
 
-    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
-                      ngx_fd_info_n " \"%s\" failed", path.data);
+    fd = of.fd;
 
-        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed", path.data);
-        }
-
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    if (!ngx_is_file(&fi)) {
+    if (!of.is_file) {
 
         if (ngx_close_file(fd) == NGX_FILE_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
@@ -163,7 +161,7 @@ ngx_http_flv_handler(ngx_http_request_t 
     }
 
     start = 0;
-    len = ngx_file_size(&fi);
+    len = of.size;
     i = 1;
 
     if (r->args.len) {
@@ -187,16 +185,9 @@ ngx_http_flv_handler(ngx_http_request_t 
 
     log->action = "sending flv to client";
 
-    cln->handler = ngx_pool_cleanup_file;
-    clnf = cln->data;
-
-    clnf->fd = fd;
-    clnf->name = path.data;
-    clnf->log = r->pool->log;
-
     r->headers_out.status = NGX_HTTP_OK;
     r->headers_out.content_length_n = len;
-    r->headers_out.last_modified_time = ngx_file_mtime(&fi);
+    r->headers_out.last_modified_time = of.mtime;
 
     if (ngx_http_set_content_type(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -237,7 +228,7 @@ ngx_http_flv_handler(ngx_http_request_t 
     }
 
     b->file_pos = start;
-    b->file_last = ngx_file_size(&fi);
+    b->file_last = of.size;
 
     b->in_file = b->file_last ? 1: 0;
     b->last_buf = 1;
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -38,7 +38,7 @@ typedef struct {
 
 
 static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
-    ngx_http_index_ctx_t *ctx);
+    ngx_http_core_loc_conf_t *clcf, ngx_http_index_ctx_t *ctx);
 static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
     ngx_http_index_ctx_t *ctx, ngx_err_t err);
 
@@ -59,17 +59,6 @@ static ngx_command_t  ngx_http_index_com
       0,
       NULL },
 
-#if (NGX_HTTP_CACHE)
-
-    { ngx_string("index_cache"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
-      ngx_http_set_cache_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_index_loc_conf_t, index_cache),
-      NULL },
-
-#endif
-
       ngx_null_command
 };
 
@@ -120,16 +109,13 @@ ngx_http_index_handler(ngx_http_request_
 {
     u_char                       *last;
     size_t                        len;
-    ngx_fd_t                      fd;
     ngx_int_t                     rc;
-    ngx_err_t                     err;
-    ngx_str_t                     uri;
+    ngx_str_t                     path, uri;
     ngx_log_t                    *log;
     ngx_uint_t                    i;
     ngx_http_index_t             *index;
     ngx_http_index_ctx_t         *ctx;
-    ngx_pool_cleanup_t           *cln;
-    ngx_pool_cleanup_file_t      *clnf;
+    ngx_open_file_info_t          of;
     ngx_http_script_code_pt       code;
     ngx_http_script_engine_t      e;
     ngx_http_core_loc_conf_t     *clcf;
@@ -151,13 +137,14 @@ ngx_http_index_handler(ngx_http_request_
 
     log = r->connection->log;
 
+    ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
     /*
      * we use context because the handler supports an async file opening,
      * and may be called several times
      */
 
-    ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
-
     ctx = ngx_http_get_module_ctx(r, ngx_http_index_module);
     if (ctx == NULL) {
 
@@ -214,12 +201,16 @@ ngx_http_index_handler(ngx_http_request_
             ctx->index.data = last;
         }
 
+        path.data = ctx->path.data;
+
         if (index[i].values == NULL) {
 
             /* index[i].name.len includes the terminating '\0' */
 
             ngx_memcpy(ctx->index.data, index[i].name.data, index[i].name.len);
 
+            path.len = (ctx->index.data + index[i].name.len - 1) - path.data;
+
         } else {
             e.ip = index[i].values->elts;
             e.pos = ctx->index.data;
@@ -234,39 +225,45 @@ ngx_http_index_handler(ngx_http_request_
                 return ngx_http_internal_redirect(r, &ctx->index, &r->args);
             }
 
+            path.len = e.pos - path.data;
+
             *e.pos++ = '\0';
         }
 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
-                       "open index \"%s\"", ctx->path.data);
+                       "open index \"%V\"", &path);
 
-        cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
-        if (cln == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
+        of.test_dir = 0;
+        of.retest = clcf->open_file_cache_retest;
+        of.errors = clcf->open_file_cache_errors;
 
-        fd = ngx_open_file(ctx->path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+        rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
 
-        if (fd == (ngx_fd_t) NGX_AGAIN) {
+#if 0
+        if (rc == NGX_AGAIN) {
             ctx->current = i;
             return NGX_AGAIN;
         }
+#endif
 
-        if (fd == NGX_INVALID_FILE) {
-            err = ngx_errno;
+        if (rc == NGX_ERROR) {
 
-            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, err,
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, of.err,
                            ngx_open_file_n " \"%s\" failed", ctx->path.data);
 
-            if (err == NGX_ENOTDIR) {
-                return ngx_http_index_error(r, ctx, err);
+            if (of.err == 0) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
 
-            } else if (err == NGX_EACCES) {
-                return ngx_http_index_error(r, ctx, err);
+            if (of.err == NGX_ENOTDIR) {
+                return ngx_http_index_error(r, ctx, of.err);
+
+            } else if (of.err == NGX_EACCES) {
+                return ngx_http_index_error(r, ctx, of.err);
             }
 
             if (!ctx->tested) {
-                rc = ngx_http_index_test_dir(r, ctx);
+                rc = ngx_http_index_test_dir(r, clcf, ctx);
 
                 if (rc != NGX_OK) {
                     return rc;
@@ -275,25 +272,16 @@ ngx_http_index_handler(ngx_http_request_
                 ctx->tested = 1;
             }
 
-            if (err == NGX_ENOENT) {
+            if (of.err == NGX_ENOENT) {
                 continue;
             }
 
-            ngx_log_error(NGX_LOG_ERR, log, err,
+            ngx_log_error(NGX_LOG_ERR, log, of.err,
                           ngx_open_file_n " \"%s\" failed", ctx->path.data);
 
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        cln->handler = ngx_pool_cleanup_file;
-        clnf = cln->data;
-
-        clnf->fd = fd;
-        clnf->name = ctx->path.data;
-        clnf->log = r->pool->log;
-
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
         uri.len = r->uri.len + ctx->index.len - 1;
 
         if (!clcf->alias) {
@@ -317,43 +305,53 @@ ngx_http_index_handler(ngx_http_request_
 
 
 static ngx_int_t
-ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx)
+ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf,
+    ngx_http_index_ctx_t *ctx)
 {
-    u_char           c;
-    ngx_uint_t       i;
-    ngx_err_t        err;
-    ngx_file_info_t  fi;
+    u_char                c;
+    ngx_str_t             path;
+    ngx_uint_t            i;
+    ngx_open_file_info_t  of;
 
     c = *(ctx->index.data - 1);
     i = (c == '/') ? 1 : 0;
     *(ctx->index.data - i) = '\0';
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http index check dir: \"%s\"", ctx->path.data);
+    path.len = (ctx->index.data - i) - ctx->path.data;
+    path.data = ctx->path.data;
 
-    if (ngx_file_info(ctx->path.data, &fi) == -1) {
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http index check dir: \"%V\"", &path);
 
-        err = ngx_errno;
+    of.test_dir = 1;
+    of.retest = clcf->open_file_cache_retest;
+    of.errors = clcf->open_file_cache_errors;
 
-        if (err == NGX_ENOENT) {
-            *(ctx->index.data - i) = c;
-            return ngx_http_index_error(r, ctx, err);
+    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
+        != NGX_OK)
+    {
+        if (of.err) {
+
+            if (of.err == NGX_ENOENT) {
+                *(ctx->index.data - i) = c;
+                return ngx_http_index_error(r, ctx, of.err);
+            }
+
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
+                          ngx_open_file_n " \"%s\" failed", path.data);
         }
 
-        ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
-                      ngx_file_info_n " \"%s\" failed", ctx->path.data);
-
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
     *(ctx->index.data - i) = c;
 
-    if (ngx_is_dir(&fi)) {
+    if (of.is_dir) {
         return NGX_OK;
     }
 
     ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                  "\"%s\" is not a directory", ctx->path.data);
+                  "\"%s\" is not a directory", path.data);
 
     return NGX_HTTP_INTERNAL_SERVER_ERROR;
 }
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -9,35 +9,10 @@
 #include <ngx_http.h>
 
 
-typedef struct {
-    ngx_http_cache_hash_t  *redirect_cache;
-} ngx_http_static_loc_conf_t;
-
-
 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
-static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
-static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
-    void *parent, void *child);
 static ngx_int_t ngx_http_static_init(ngx_conf_t *cf);
 
 
-static ngx_command_t  ngx_http_static_commands[] = {
-
-#if (NGX_HTTP_CACHE)
-
-    { ngx_string("redirect_cache"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
-      ngx_http_set_cache_slot,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_static_loc_conf_t, redirect_cache),
-      NULL },
-
-#endif
-
-      ngx_null_command
-};
-
-
 ngx_http_module_t  ngx_http_static_module_ctx = {
     NULL,                                  /* preconfiguration */
     ngx_http_static_init,                  /* postconfiguration */
@@ -48,15 +23,15 @@ ngx_http_module_t  ngx_http_static_modul
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
 
-    ngx_http_static_create_loc_conf,       /* create location configuration */
-    ngx_http_static_merge_loc_conf         /* merge location configuration */
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
 };
 
 
 ngx_module_t  ngx_http_static_module = {
     NGX_MODULE_V1,
     &ngx_http_static_module_ctx,           /* module context */
-    ngx_http_static_commands,              /* module directives */
+    NULL,                                  /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     NULL,                                  /* init master */
     NULL,                                  /* init module */
@@ -75,16 +50,13 @@ ngx_http_static_handler(ngx_http_request
     u_char                    *last, *location;
     size_t                     root;
     ngx_fd_t                   fd;
+    ngx_str_t                  path;
     ngx_int_t                  rc;
     ngx_uint_t                 level;
-    ngx_str_t                  path;
-    ngx_err_t                  err;
     ngx_log_t                 *log;
     ngx_buf_t                 *b;
     ngx_chain_t                out;
-    ngx_file_info_t            fi;
-    ngx_pool_cleanup_t        *cln;
-    ngx_pool_cleanup_file_t   *clnf;
+    ngx_open_file_info_t       of;
     ngx_http_core_loc_conf_t  *clcf;
 
     if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
@@ -118,75 +90,68 @@ ngx_http_static_handler(ngx_http_request
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    path.len = last - path.data;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", path.data);
 
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
-    if (cln == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+    of.test_dir = 0;
+    of.retest = clcf->open_file_cache_retest;
+    of.errors = clcf->open_file_cache_errors;
+
+    rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
+
+    if (rc == NGX_ERROR) {
 
-    if (fd == NGX_INVALID_FILE) {
-        err = ngx_errno;
+        switch (of.err) {
+
+        case 0:
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
 
-        if (err == NGX_ENOENT
-            || err == NGX_ENOTDIR
-            || err == NGX_ENAMETOOLONG)
-        {
+        case NGX_ENOENT:
+        case NGX_ENOTDIR:
+        case NGX_ENAMETOOLONG:
+
             level = NGX_LOG_ERR;
             rc = NGX_HTTP_NOT_FOUND;
+            break;
 
-        } else if (err == NGX_EACCES) {
+        case NGX_EACCES:
+
             level = NGX_LOG_ERR;
             rc = NGX_HTTP_FORBIDDEN;
+            break;
 
-        } else {
+        default:
+
             level = NGX_LOG_CRIT;
             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+            break;
         }
 
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
         if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
-            ngx_log_error(level, log, err,
+            ngx_log_error(level, log, of.err,
                           ngx_open_file_n " \"%s\" failed", path.data);
         }
 
         return rc;
     }
 
+    fd = of.fd;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);
 
-    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
-        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
-                      ngx_fd_info_n " \"%s\" failed", path.data);
-
-        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed", path.data);
-        }
-
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    if (ngx_is_dir(&fi)) {
+    if (of.is_dir) {
 
         ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
 
-        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed", path.data);
-        }
-
         r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
         if (r->headers_out.location == NULL) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
         if (!clcf->alias && clcf->root_lengths == NULL) {
             location = path.data + clcf->root.len;
 
@@ -214,15 +179,10 @@ ngx_http_static_handler(ngx_http_request
 
 #if !(NGX_WIN32) /* the not regular files are probably Unix specific */
 
-    if (!ngx_is_file(&fi)) {
+    if (!of.is_file) {
         ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                       "\"%s\" is not a regular file", path.data);
 
-        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed", path.data);
-        }
-
         return NGX_HTTP_NOT_FOUND;
     }
 
@@ -230,22 +190,15 @@ ngx_http_static_handler(ngx_http_request
 
     log->action = "sending response to client";
 
-    cln->handler = ngx_pool_cleanup_file;
-    clnf = cln->data;
-
-    clnf->fd = fd;
-    clnf->name = path.data;
-    clnf->log = r->pool->log;
-
     r->headers_out.status = NGX_HTTP_OK;
-    r->headers_out.content_length_n = ngx_file_size(&fi);
-    r->headers_out.last_modified_time = ngx_file_mtime(&fi);
+    r->headers_out.content_length_n = of.size;
+    r->headers_out.last_modified_time = of.mtime;
 
     if (ngx_http_set_content_type(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (r != r->main && ngx_file_size(&fi) == 0) {
+    if (r != r->main && of.size == 0) {
         return ngx_http_send_header(r);
     }
 
@@ -270,7 +223,7 @@ ngx_http_static_handler(ngx_http_request
     }
 
     b->file_pos = 0;
-    b->file_last = ngx_file_size(&fi);
+    b->file_last = of.size;
 
     b->in_file = b->file_last ? 1: 0;
     b->last_buf = (r == r->main) ? 1: 0;
@@ -287,36 +240,6 @@ ngx_http_static_handler(ngx_http_request
 }
 
 
-static void *
-ngx_http_static_create_loc_conf(ngx_conf_t *cf)
-{
-    ngx_http_static_loc_conf_t  *conf;
-
-    conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t));
-    if (conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->redirect_cache = NULL;
-
-    return conf;
-}
-
-
-static char *
-ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
-{
-    ngx_http_static_loc_conf_t  *prev = parent;
-    ngx_http_static_loc_conf_t  *conf = child;
-
-    if (conf->redirect_cache == NULL) {
-        conf->redirect_cache = prev->redirect_cache;
-    }
-
-    return NGX_CONF_OK;
-}
-
-
 static ngx_int_t
 ngx_http_static_init(ngx_conf_t *cf)
 {
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -605,15 +605,15 @@ void
 sendfile(r, filename, offset = -1, bytes = 0)
     CODE:
 
-    ngx_http_request_t       *r;
-    char                     *filename;
-    int                       offset;
-    size_t                    bytes;
-    ngx_fd_t                  fd;
-    ngx_buf_t                *b;
-    ngx_file_info_t           fi;
-    ngx_pool_cleanup_t       *cln;
-    ngx_pool_cleanup_file_t  *clnf;
+    ngx_http_request_t        *r;
+    char                      *filename;
+    int                        offset;
+    size_t                     bytes;
+    ngx_int_t                  rc;
+    ngx_str_t                  path;
+    ngx_buf_t                 *b;
+    ngx_open_file_info_t       of;
+    ngx_http_core_loc_conf_t  *clcf;
 
     ngx_http_perl_set_request(r);
 
@@ -636,14 +636,29 @@ sendfile(r, filename, offset = -1, bytes
         XSRETURN_EMPTY;
     }
 
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
-    if (cln == NULL) {
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+    
+    of.test_dir = 0;
+    of.retest = clcf->open_file_cache_retest; 
+    of.errors = clcf->open_file_cache_errors; 
+
+    path.len = ngx_strlen(filename);
+
+    path.data = ngx_pcalloc(r->pool, path.len + 1);
+    if (path.data == NULL) {
         XSRETURN_EMPTY;
     }
 
-    fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+    (void) ngx_cpystrn(path.data, filename, path.len + 1);
+ 
+    rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
 
-    if (fd == NGX_INVALID_FILE) {
+    if (rc == NGX_ERROR) {
+
+        if (of.err == 0) {
+            XSRETURN_EMPTY;
+        }
+
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
                       ngx_open_file_n " \"%s\" failed", filename);
         XSRETURN_EMPTY;
@@ -654,34 +669,15 @@ sendfile(r, filename, offset = -1, bytes
     }
 
     if (bytes == 0) {
-        if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_fd_info_n " \"%s\" failed", filename);
-
-            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed", filename);
-            }
-
-            XSRETURN_EMPTY;
-        }
-
-        bytes = ngx_file_size(&fi) - offset;
+        bytes = of.size - offset;
     }
 
-    cln->handler = ngx_pool_cleanup_file;
-    clnf = cln->data;
-
-    clnf->fd = fd;
-    clnf->name = (u_char *) "";
-    clnf->log = r->pool->log;
-
     b->in_file = 1;
 
     b->file_pos = offset;
     b->file_last = offset + bytes;
 
-    b->file->fd = fd;
+    b->file->fd = of.fd;
     b->file->log = r->connection->log;
 
     (void) ngx_http_perl_output(r, b);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -61,6 +61,8 @@ static char *ngx_http_core_limit_except(
     void *conf);
 static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
 static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -448,16 +450,26 @@ static ngx_command_t  ngx_http_core_comm
       0,
       NULL },
 
-#if (NGX_HTTP_CACHE)
-
     { ngx_string("open_file_cache"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE4,
-      ngx_http_set_cache_slot,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+      ngx_http_core_open_file_cache,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, open_file_cache),
+      NULL },
+
+    { ngx_string("open_file_cache_retest"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_sec_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
-      offsetof(ngx_http_core_loc_conf_t, open_files),
+      offsetof(ngx_http_core_loc_conf_t, open_file_cache_retest),
       NULL },
 
-#endif
+    { ngx_string("open_file_cache_errors"),
+      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, open_file_cache_errors),
+      NULL },
 
       ngx_null_command
 };
@@ -2360,6 +2372,9 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->recursive_error_pages = NGX_CONF_UNSET;
     lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
     lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
+    lcf->open_file_cache = NGX_CONF_UNSET_PTR;
+    lcf->open_file_cache_retest = NGX_CONF_UNSET;
+    lcf->open_file_cache_errors = NGX_CONF_UNSET;
 
     return lcf;
 }
@@ -2543,9 +2558,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->recursive_error_pages,
                               prev->recursive_error_pages, 0);
 
-    if (conf->open_files == NULL) {
-        conf->open_files = prev->open_files;
-    }
+    ngx_conf_merge_ptr_value(conf->open_file_cache,
+                             prev->open_file_cache, NULL);
+
+    ngx_conf_merge_sec_value(conf->open_file_cache_retest,
+                             prev->open_file_cache_retest, 60);
+
+    ngx_conf_merge_sec_value(conf->open_file_cache_errors,
+                             prev->open_file_cache_errors, 0);
 
     return NGX_CONF_OK;
 }
@@ -3162,6 +3182,82 @@ ngx_http_core_error_page(ngx_conf_t *cf,
 
 
 static char *
+ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_core_loc_conf_t *lcf = conf;
+
+    time_t       inactive;
+    ngx_str_t   *value, s;
+    ngx_int_t    max;
+    ngx_uint_t   i;
+
+    if (lcf->open_file_cache != NGX_CONF_UNSET_PTR) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    max = 0;
+    inactive = 60;
+
+    for (i = 1; i < cf->args->nelts; i++) {
+
+        if (ngx_strncmp(value[i].data, "max=", 4) == 0) {
+
+            max = ngx_atoi(value[i].data + 4, value[i].len - 4);
+            if (max == NGX_ERROR) {
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
+        if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) {
+
+            s.len = value[i].len - 9;
+            s.data = value[i].data + 9;
+
+            inactive = ngx_parse_time(&s, 1);
+            if (inactive < 0) {
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
+        if (ngx_strcmp(value[i].data, "off") == 0) {
+
+            lcf->open_file_cache = NULL;
+
+            continue;
+        }
+
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid \"open_file_cache\" parameter \"%V\"",
+                           &value[i]);
+        return NGX_CONF_ERROR;
+    }
+
+    if (lcf->open_file_cache == NULL) {
+        return NGX_CONF_OK;
+    }
+
+    if (max == 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "\"open_file_cache\" must have \"max\" parameter");
+        return NGX_CONF_ERROR;
+    }
+
+    lcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
+    if (lcf->open_file_cache) {
+        return NGX_CONF_OK;
+    }
+
+    return NGX_CONF_ERROR;
+}
+
+
+static char *
 ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_http_core_loc_conf_t *lcf = conf;
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -290,7 +290,9 @@ struct ngx_http_core_loc_conf_s {
 
     ngx_path_t   *client_body_temp_path;   /* client_body_temp_path */
 
-    ngx_http_cache_hash_t  *open_files;
+    ngx_open_file_cache_t  *open_file_cache;
+    time_t        open_file_cache_retest;
+    ngx_flag_t    open_file_cache_errors;
 
     ngx_log_t    *err_log;
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -952,8 +952,10 @@ ngx_http_script_not_equal_code(ngx_http_
 void
 ngx_http_script_file_code(ngx_http_script_engine_t *e)
 {
-    ngx_err_t                     err;
-    ngx_file_info_t               fi;
+    ngx_str_t                     path;
+    ngx_http_request_t           *r;
+    ngx_open_file_info_t          of;
+    ngx_http_core_loc_conf_t     *clcf;
     ngx_http_variable_value_t    *value;
     ngx_http_script_file_code_t  *code;
 
@@ -962,14 +964,25 @@ ngx_http_script_file_code(ngx_http_scrip
     code = (ngx_http_script_file_code_t *) e->ip;
     e->ip += sizeof(ngx_http_script_file_code_t);
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
-                   "http script file op %p", code->op);
+    path.len = value->len - 1;
+    path.data = value->data;
+
+    r = e->request;
+
+    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "http script file op %p \"%V\"", code->op, &path);
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (ngx_file_info(value->data, &fi) == -1) {
-        err = ngx_errno;
+    of.test_dir = 0;
+    of.retest = clcf->open_file_cache_retest;
+    of.errors = clcf->open_file_cache_errors;
 
-        if (err != NGX_ENOENT && err != NGX_ENOTDIR) {
-            ngx_log_error(NGX_LOG_CRIT, e->request->connection->log, err,
+    if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
+        == NGX_ERROR)
+    {
+        if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
                           ngx_file_info_n " \"%s\" failed", value->data);
         }
 
@@ -993,69 +1006,57 @@ ngx_http_script_file_code(ngx_http_scrip
 
     switch (code->op) {
     case ngx_http_script_file_plain:
-        if (ngx_is_file(&fi)) {
+        if (of.is_file) {
              goto true;
         }
         goto false;
 
     case ngx_http_script_file_not_plain:
-        if (ngx_is_file(&fi)) {
+        if (of.is_file) {
             goto false;
         }
         goto true;
 
     case ngx_http_script_file_dir:
-        if (ngx_is_dir(&fi)) {
+        if (of.is_dir) {
              goto true;
         }
         goto false;
 
     case ngx_http_script_file_not_dir:
-        if (ngx_is_dir(&fi)) {
+        if (of.is_dir) {
             goto false;
         }
         goto true;
 
     case ngx_http_script_file_exists:
-        if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) {
+        if (of.is_file || of.is_dir || of.is_link) {
              goto true;
         }
         goto false;
 
     case ngx_http_script_file_not_exists:
-        if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) {
+        if (of.is_file || of.is_dir || of.is_link) {
             goto false;
         }
         goto true;
 
-#if (NGX_WIN32)
-
     case ngx_http_script_file_exec:
-        goto false;
-
-    case ngx_http_script_file_not_exec:
-        goto true;
-
-#else
-
-    case ngx_http_script_file_exec:
-        if (ngx_is_exec(&fi)) {
+        if (of.is_exec) {
              goto true;
         }
         goto false;
 
     case ngx_http_script_file_not_exec:
-        if (ngx_is_exec(&fi)) {
+        if (of.is_exec) {
             goto false;
         }
         goto true;
-
-#endif
     }
 
 false:
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http script file op false");
 
     *value = ngx_http_variable_null_value;