changeset 201:267ea1d98683

nginx-0.0.1-2003-11-30-23:03:18 import
author Igor Sysoev <igor@sysoev.ru>
date Sun, 30 Nov 2003 20:03:18 +0000
parents abeaebe0a33c
children 74994aeef848
files auto/cc auto/sources src/core/nginx.c src/core/ngx_config.h src/core/ngx_core.h src/core/ngx_crc.h src/core/ngx_log.c src/core/ngx_log.h src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_static_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_cache.c src/http/ngx_http_cache.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/os/unix/ngx_freebsd_sendfile_chain.c src/os/unix/ngx_linux_sendfile_chain.c
diffstat 21 files changed, 1238 insertions(+), 861 deletions(-) [+]
line wrap: on
line diff
--- a/auto/cc
+++ b/auto/cc
@@ -24,6 +24,8 @@ case $CC in
          # debug
          CFLAGS="$CFLAGS -g"
 
+         CFLAGS="$CFLAGS -D HAVE_GCC_VARIADIC_MACROS=1"
+
          OBJEXT=o
          OBJOUT="-o "
          BINOUT="-o "
@@ -48,6 +50,8 @@ case $CC in
          # stop on warning
          CFLAGS="$CFLAGS -Werror"
 
+         CFLAGS="$CFLAGS -D HAVE_C99_VARIADIC_MACROS=1"
+
          OBJEXT=o
          OBJOUT="-o "
          BINOUT="-o "
--- a/auto/sources
+++ b/auto/sources
@@ -14,6 +14,7 @@ CORE_DEPS="src/core/nginx.h \
             src/core/ngx_parse.h \
             src/core/ngx_inet.h \
             src/core/ngx_file.h \
+            src/core/ngx_crc.h \
             src/core/ngx_regex.h \
             src/core/ngx_times.h \
             src/core/ngx_connection.h \
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -134,7 +134,7 @@ int main(int argc, char *const *argv)
     /* life cycle */
 
     for ( ;; ) {
-        /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG;
+        /* STUB */ cycle->log->log_level = NGX_LOG_DEBUG|NGX_LOG_DEBUG_HTTP;
 
 #if 0
 
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -38,6 +38,9 @@
 typedef int    ngx_int_t;
 typedef u_int  ngx_uint_t;
 
+/* STUB: autoconf */
+#define PTR_FMT  "%X"
+
 #include <ngx_auto_config.h>
 
 
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -28,6 +28,7 @@ typedef struct ngx_connection_s  ngx_con
 #include <ngx_types.h>
 #include <ngx_file.h>
 #include <ngx_files.h>
+#include <ngx_crc.h>
 #include <ngx_regex.h>
 #include <ngx_times.h>
 #include <ngx_inet.h>
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_crc.h
@@ -0,0 +1,26 @@
+#ifndef _NGX_CRC_H_INCLUDED_
+#define _NGX_CRC_H_INCLUDED_
+
+
+/* 32-bit crc16 */
+
+ngx_inline static uint32_t ngx_crc(char *data, size_t len)
+{
+    uint32_t  sum;
+    
+    for (sum = 0; len; len--) {
+        /*
+         * gcc 2.95.2 x86 and icc 7.1.006 compile that operator
+         *                                into the single rol opcode.
+         * msvc 6.0sp2 compiles it into four opcodes.
+         */
+        sum = sum >> 1 | sum << 31;
+
+        sum += *data++;
+    }
+
+    return sum;
+}
+
+
+#endif /* _NGX_CRC_H_INCLUDED_ */
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -169,12 +169,12 @@ void ngx_log_error(int level, ngx_log_t 
 }
 
 
-void ngx_log_debug_core(ngx_log_t *log, const char *fmt, ...)
+void ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...)
 {
     va_list    args;
 
     va_start(args, fmt);
-    ngx_log_error_core(NGX_LOG_DEBUG, log, 0, fmt, args);
+    ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt, args);
     va_end(args);
 }
 
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -6,17 +6,17 @@
 #include <ngx_core.h>
 
 
-typedef enum {
-    NGX_LOG_STDERR = 0,
-    NGX_LOG_EMERG,
-    NGX_LOG_ALERT,
-    NGX_LOG_CRIT,
-    NGX_LOG_ERR,
-    NGX_LOG_WARN,
-    NGX_LOG_NOTICE,
-    NGX_LOG_INFO,
-    NGX_LOG_DEBUG
-} ngx_log_e;
+#define NGX_LOG_STDERR          0
+#define NGX_LOG_EMERG           1
+#define NGX_LOG_ALERT           2
+#define NGX_LOG_CRIT            3
+#define NGX_LOG_ERR             4
+#define NGX_LOG_WARN            5
+#define NGX_LOG_NOTICE          6
+#define NGX_LOG_INFO            7
+#define NGX_LOG_DEBUG           8
+
+#define NGX_LOG_DEBUG_HTTP   0x80
 
 
 /*
@@ -71,13 +71,6 @@ struct ngx_log_s {
     ngx_open_file_t     *file;
     void                *data;
     ngx_log_handler_pt   handler;
-
-#if 0
-/* STUB */
-    char     *action;
-    char     *context;
-/* */
-#endif
 };
 
 #define MAX_ERROR_STR	2048
@@ -85,6 +78,8 @@ struct ngx_log_s {
 #define _               ,
 
 
+/*********************************/
+
 #if (HAVE_GCC_VARIADIC_MACROS)
 
 #define HAVE_VARIADIC_MACROS  1
@@ -94,7 +89,7 @@ struct ngx_log_s {
 
 #if (NGX_DEBUG)
 #define ngx_log_debug(log, args...) \
-    if (log->log_level == NGX_LOG_DEBUG) \
+    if (log->log_level & NGX_LOG_DEBUG) \
         ngx_log_error_core(NGX_LOG_DEBUG, log, 0, args)
 #else
 #define ngx_log_debug(log, args...)
@@ -110,6 +105,7 @@ struct ngx_log_s {
 void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
                         const char *fmt, ...);
 
+/*********************************/
 
 #elif (HAVE_C99_VARIADIC_MACROS)
 
@@ -136,13 +132,16 @@ void ngx_log_error_core(int level, ngx_l
 void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
                         const char *fmt, ...);
 
+/*********************************/
 
 #else /* NO VARIADIC MACROS */
 
+#define HAVE_VARIADIC_MACROS  0
+
 #if (NGX_DEBUG)
 #define ngx_log_debug(log, text) \
     if (log->log_level == NGX_LOG_DEBUG) \
-        ngx_log_debug_core(log, text)
+        ngx_log_debug_core(log, 0, text)
 #else
 #define ngx_log_debug(log, text)
 #endif
@@ -158,13 +157,57 @@ void ngx_log_error(int level, ngx_log_t 
                    const char *fmt, ...);
 void ngx_log_error_core(int level, ngx_log_t *log, ngx_err_t err,
                         const char *fmt, va_list args);
-void ngx_log_debug_core(ngx_log_t *log, const char *fmt, ...);
+void ngx_log_debug_core(ngx_log_t *log, ngx_err_t err, const char *fmt, ...);
 void ngx_assert_core(ngx_log_t *log, const char *fmt, ...);
 
 
 #endif /* VARIADIC MACROS */
 
 
+/*********************************/
+
+#if (HAVE_VARIADIC_MACROS)
+
+#if (NGX_DEBUG)
+#define ngx_log_debug0(level, log, err, fmt) \
+    if (log->log_level & level) \
+        ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt)
+#else
+#define ngx_log_debug0(level, log, err, fmt)
+#endif
+
+#if (NGX_DEBUG)
+#define ngx_log_debug1(level, log, err, fmt, arg1) \
+    if (log->log_level & level) \
+        ngx_log_error_core(NGX_LOG_DEBUG, log, err, fmt, arg1)
+#else
+#define ngx_log_debug1(level, log, err, fmt, arg1)
+#endif
+
+/*********************************/
+
+#else /* NO VARIADIC MACROS */
+
+#if (NGX_DEBUG)
+#define ngx_log_debug0(level, log, err, fmt) \
+    if (log->log_level & level) \
+        ngx_log_debug_core(log, err, fmt)
+#else
+#define ngx_log_debug0(level, log, err, fmt)
+#endif
+
+#if (NGX_DEBUG)
+#define ngx_log_debug1(level, log, err, fmt, arg1) \
+    if (log->log_level & level) \
+        ngx_log_debug_core(log, err, fmt, arg1)
+#else
+#define ngx_log_debug1(level, log, err, fmt, arg1)
+#endif
+#endif
+
+
+/*********************************/
+
 #define ngx_log_alloc_log(pool, log)  ngx_palloc(pool, log, sizeof(ngx_log_t))
 #define ngx_log_copy_log(new, old)    ngx_memcpy(new, old, sizeof(ngx_log_t))
 
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -7,13 +7,17 @@
 typedef struct {
     ngx_array_t             indices;
     size_t                  max_index_len;
-    ngx_http_cache_hash_t  *cache;
-} ngx_http_index_conf_t;
+    ngx_http_cache_hash_t  *index_cache;
+} ngx_http_index_loc_conf_t;
 
 
 typedef struct {
-    int          index;
-    unsigned     tested:1;
+    ngx_int_t          index;
+    char              *last;
+    ngx_str_t          path;
+    ngx_str_t          redirect;
+    ngx_http_cache_t  *cache;
+    unsigned           tested:1;
 } ngx_http_index_ctx_t;
 
 
@@ -26,8 +30,8 @@ static ngx_int_t ngx_http_index_error(ng
                                       ngx_http_index_ctx_t *ctx, ngx_err_t err);
 
 static int ngx_http_index_init(ngx_cycle_t *cycle);
-static void *ngx_http_index_create_conf(ngx_conf_t *cf);
-static char *ngx_http_index_merge_conf(ngx_conf_t *cf,
+static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf,
                                        void *parent, void *child);
 static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
                                       void *conf);
@@ -43,10 +47,10 @@ static ngx_command_t  ngx_http_index_com
       NULL },
 
     { ngx_string("index_cache"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+      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_conf_t, cache),
+      offsetof(ngx_http_index_loc_conf_t, index_cache),
       NULL },
 
       ngx_null_command
@@ -62,8 +66,8 @@ ngx_http_module_t  ngx_http_index_module
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
 
-    ngx_http_index_create_conf,            /* create location configration */
-    ngx_http_index_merge_conf              /* merge location configration */
+    ngx_http_index_create_loc_conf,        /* create location configration */
+    ngx_http_index_merge_loc_conf          /* merge location configration */
 };
 
 
@@ -89,72 +93,77 @@ ngx_module_t  ngx_http_index_module = {
 
 int ngx_http_index_handler(ngx_http_request_t *r)
 {
-    char                      *name, *file;
-    uint32_t                   crc;
-    ngx_int_t                  rc;
-    ngx_str_t                  redirect, *index;
-    ngx_err_t                  err;
-    ngx_fd_t                   fd;
-    ngx_http_cache_t          *cache;
-    ngx_http_index_ctx_t      *ctx;
-    ngx_http_index_conf_t     *ilcf;
-    ngx_http_core_loc_conf_t  *clcf;
+    char                       *name;
+    uint32_t                    crc;
+    size_t                      len;
+    ngx_fd_t                    fd;
+    ngx_int_t                   rc;
+    ngx_str_t                  *index;
+    ngx_err_t                   err;
+    ngx_log_t                  *log;
+    ngx_http_index_ctx_t       *ctx;
+    ngx_http_core_loc_conf_t   *clcf;
+    ngx_http_index_loc_conf_t  *ilcf;
 
     if (r->uri.data[r->uri.len - 1] != '/') {
         return NGX_DECLINED;
     }
 
-    ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
-
-    if (ilcf->cache) {
-        cache = ngx_http_cache_get(ilcf->cache, &r->uri, &crc);
-
-ngx_log_debug(r->connection->log, "index cache get: %x" _ cache);
-
-        if (cache && ilcf->cache->update >= ngx_cached_time - cache->updated) {
-
-            cache->accessed = ngx_cached_time;
+    log = r->connection->log;
 
-            redirect.len = cache->data.value.len;
-            if (!(redirect.data = ngx_palloc(r->pool, redirect.len + 1))) {
-                ngx_http_cache_unlock(ilcf->cache, cache, r->connection->log);
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
+    /*
+     * we use context because the handler supports an async file opening
+     * and thus can be called several times
+     */
 
-            ngx_memcpy(redirect.data, cache->data.value.data, redirect.len + 1);
-            ngx_http_cache_unlock(ilcf->cache, cache, r->connection->log);
-
-            return ngx_http_internal_redirect(r, &redirect, NULL);
-        }
-
-    } else {
-        cache = NULL;
-    }
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+    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) {
         ngx_http_create_ctx(r, ctx, ngx_http_index_module,
                             sizeof(ngx_http_index_ctx_t),
                             NGX_HTTP_INTERNAL_SERVER_ERROR);
-    }
+
+        if (ilcf->index_cache) {
+            ctx->cache = ngx_http_cache_get(ilcf->index_cache, NULL,
+                                            &r->uri, &crc);
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                           "http index cache get: " PTR_FMT, ctx->cache);
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+            if (ctx->cache && ctx->cache->valid) {
+
+                ctx->cache->accessed = ngx_cached_time;
+
+                ctx->redirect.len = ctx->cache->data.value.len;
+                ctx->redirect.data = ngx_palloc(r->pool, ctx->redirect.len + 1);
+                if (ctx->redirect.data == NULL) {
+                    ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
+                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                }
 
-    if (r->path.data == NULL) {
-        r->path_allocated = clcf->doc_root.len + r->uri.len
-                                                         + ilcf->max_index_len;
-        ngx_test_null(r->path.data,
-                      ngx_palloc(r->pool, r->path_allocated),
-                      NGX_HTTP_INTERNAL_SERVER_ERROR);
+                ngx_memcpy(ctx->redirect.data, ctx->cache->data.value.data,
+                           ctx->redirect.len + 1);
+                ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
+
+                return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
+            }
+
+        } else {
+            ctx->cache = NULL;
+        }
 
-        redirect.data = ngx_cpymem(r->path.data, clcf->doc_root.data,
-                                   clcf->doc_root.len);
-        file = ngx_cpystrn(redirect.data, r->uri.data, r->uri.len + 1);
-        r->path.len = file - r->path.data;
+        len = clcf->doc_root.len + r->uri.len + ilcf->max_index_len;
+        if (!(ctx->path.data = ngx_palloc(r->pool, len))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
 
-    } else{
-        redirect.data = r->path.data + r->path.len;
-        file = redirect.data + r->uri.len;
+        ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->doc_root.data,
+                                        clcf->doc_root.len);
+        ctx->last = ngx_cpystrn(ctx->redirect.data, r->uri.data,
+                                r->uri.len + 1);
+        ctx->path.len = ctx->last - ctx->path.data;
     }
 
     index = ilcf->indices.elts;
@@ -164,8 +173,9 @@ ngx_log_debug(r->connection->log, "index
             name = index[ctx->index].data;
 
         } else {
-            ngx_memcpy(file, index[ctx->index].data, index[ctx->index].len + 1);
-            name = r->path.data;
+            ngx_memcpy(ctx->last, index[ctx->index].data,
+                       index[ctx->index].len + 1);
+            name = ctx->path.data;
         }
 
         fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN);
@@ -177,8 +187,8 @@ ngx_log_debug(r->connection->log, "index
         if (fd == NGX_INVALID_FILE) {
             err = ngx_errno;
 
-ngx_log_error(NGX_LOG_DEBUG, r->connection->log, err,
-              "DEBUG: " ngx_open_file_n " %s failed", name);
+            ngx_log_error(NGX_LOG_DEBUG, log, err,
+                          "debug: " ngx_open_file_n " %s failed", name);
 
             if (err == NGX_ENOTDIR) {
                 return ngx_http_index_error(r, ctx, err);
@@ -201,80 +211,68 @@ ngx_log_error(NGX_LOG_DEBUG, r->connecti
                 continue;
             }
 
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
+            ngx_log_error(NGX_LOG_ERR, log, err,
                           ngx_open_file_n " %s failed", name);
 
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
+
+        /* STUB: open file cache */
+
         r->file.name.data = name;
         r->file.fd = fd;
 
         if (index[ctx->index].data[0] == '/') {
             r->file.name.len = index[ctx->index].len;
-            redirect.len = index[ctx->index].len;
-            redirect.data = index[ctx->index].data;
+            ctx->redirect.len = index[ctx->index].len;
+            ctx->redirect.data = index[ctx->index].data;
 
         } else {
-            redirect.len = r->uri.len + index[ctx->index].len;
+            ctx->redirect.len = r->uri.len + index[ctx->index].len;
             r->file.name.len = clcf->doc_root.len + r->uri.len
                                                        + index[ctx->index].len;
         }
 
-        if (ilcf->cache) {
+        /**/
+
+
+        if (ilcf->index_cache) {
 
-            if (cache) {
-                if (redirect.len == cache->data.value.len
-                    && ngx_memcmp(cache->data.value.data, redirect.data,
-                                                            redirect.len) == 0)
+            if (ctx->cache) {
+                if (ctx->redirect.len == ctx->cache->data.value.len
+                    && ngx_memcmp(ctx->cache->data.value.data,
+                                  ctx->redirect.data, ctx->redirect.len) == 0)
                 {
-                    cache->accessed = ngx_cached_time;
-                    cache->updated = ngx_cached_time;
-                    ngx_http_cache_unlock(ilcf->cache, cache,
-                                          r->connection->log);
+                    ctx->cache->accessed = ngx_cached_time;
+                    ctx->cache->updated = ngx_cached_time;
+                    ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
 
-                    return ngx_http_internal_redirect(r, &redirect, NULL);
-
-                } else {
-                    if (redirect.len > cache->data.value.len) {
-                         ngx_free(cache->data.value.data);
-                         cache->data.value.data = NULL;
-                    }
+                    return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
                 }
             }
 
-            if (cache == NULL) {
-                cache = ngx_http_cache_alloc(ilcf->cache, &r->uri, crc,
-                                             r->connection->log);
-            }
+            ctx->redirect.len++;
+            ctx->cache = ngx_http_cache_alloc(ilcf->index_cache, ctx->cache,
+                                              NULL, &r->uri, crc,
+                                              &ctx->redirect, log);
+            ctx->redirect.len--;
 
-ngx_log_debug(r->connection->log, "index cache alloc: %x" _ cache);
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                           "http index cache alloc: " PTR_FMT, ctx->cache);
 
-            if (cache) {
-                cache->fd = NGX_INVALID_FILE;
-                cache->accessed = ngx_cached_time;
-                cache->last_modified = 0;
-                cache->updated = ngx_cached_time;
-
-                cache->data.value.len = redirect.len;
-                if (cache->data.value.data == NULL) {
-                    cache->data.value.data = ngx_alloc(redirect.len + 1,
-                                                       r->connection->log);
-                    if (cache->data.value.data == NULL) {
-                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-                    }
-                }
-
-                ngx_memcpy(cache->data.value.data, redirect.data,
-                           redirect.len + 1);
+            if (ctx->cache) {
+                ctx->cache->fd = NGX_INVALID_FILE;
+                ctx->cache->accessed = ngx_cached_time;
+                ctx->cache->last_modified = 0;
+                ctx->cache->updated = ngx_cached_time;
+                ctx->cache->valid = 1;
+                ctx->cache->memory = 1;
+                ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log);
             }
         }
 
-        if (cache) {
-            ngx_http_cache_unlock(ilcf->cache, cache, r->connection->log);
-        }
-
-        return ngx_http_internal_redirect(r, &redirect, NULL);
+        return ngx_http_internal_redirect(r, &ctx->redirect, NULL);
     }
 
     return NGX_DECLINED;
@@ -286,27 +284,27 @@ static ngx_int_t ngx_http_index_test_dir
 {
     ngx_err_t  err;
 
-    r->path.data[r->path.len - 1] = '\0';
-    r->path.data[r->path.len] = '\0';
+    ctx->path.data[ctx->path.len - 1] = '\0';
+    ctx->path.data[ctx->path.len] = '\0';
 
-ngx_log_debug(r->connection->log, "IS_DIR: %s" _ r->path.data);
+ngx_log_debug(r->connection->log, "IS_DIR: %s" _ ctx->path.data);
 
-    if (ngx_file_info(r->path.data, &r->file.info) == -1) {
+    if (ngx_file_info(ctx->path.data, &r->file.info) == -1) {
 
         err = ngx_errno;
 
         if (err == NGX_ENOENT) {
-            r->path.data[r->path.len - 1] = '/';
+            ctx->path.data[ctx->path.len - 1] = '/';
             return ngx_http_index_error(r, ctx, err);
         }
 
         ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
-                      ngx_file_info_n " %s failed", r->path.data);
+                      ngx_file_info_n " %s failed", ctx->path.data);
 
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->path.data[r->path.len - 1] = '/';
+    ctx->path.data[ctx->path.len - 1] = '/';
 
     if (ngx_is_dir(&r->file.info)) {
         return NGX_OK;
@@ -322,13 +320,13 @@ static ngx_int_t ngx_http_index_error(ng
 {
     if (err == NGX_EACCES) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                      "\"%s\" is forbidden", r->path.data);
+                      "\"%s\" is forbidden", ctx->path.data);
     
         return NGX_HTTP_FORBIDDEN;
     }
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                  "\"%s\" is not found", r->path.data);
+                  "\"%s\" is not found", ctx->path.data);
     return NGX_HTTP_NOT_FOUND;
 }
 
@@ -342,27 +340,29 @@ static int ngx_http_index_init(ngx_cycle
     ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
     cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
 
-    ngx_test_null(h, ngx_push_array(
-                             &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
-                  NGX_ERROR);
+    h = ngx_push_array(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
     *h = ngx_http_index_handler;
 
     return NGX_OK;
 }
 
 
-static void *ngx_http_index_create_conf(ngx_conf_t *cf)
+static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf)
 {
-    ngx_http_index_conf_t  *conf;
+    ngx_http_index_loc_conf_t  *conf;
 
-    ngx_test_null(conf, ngx_palloc(cf->pool, sizeof(ngx_http_index_conf_t)),
+    ngx_test_null(conf, ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)),
                   NGX_CONF_ERROR);
 
     ngx_init_array(conf->indices, cf->pool, 3, sizeof(ngx_str_t),
                    NGX_CONF_ERROR);
     conf->max_index_len = 0;
 
-    conf->cache = NULL;
+    conf->index_cache = NULL;
 
     return conf;
 }
@@ -370,18 +370,18 @@ static void *ngx_http_index_create_conf(
 
 /* TODO: remove duplicate indices */
 
-static char *ngx_http_index_merge_conf(ngx_conf_t *cf,
-                                       void *parent, void *child)
+static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf,
+                                           void *parent, void *child)
 {
-    ngx_http_index_conf_t *prev = parent;
-    ngx_http_index_conf_t *conf = child;
+    ngx_http_index_loc_conf_t  *prev = parent;
+    ngx_http_index_loc_conf_t  *conf = child;
 
     int         i;
     ngx_str_t  *index, *prev_index;
 
     if (conf->max_index_len == 0) {
         if (prev->max_index_len != 0) {
-            ngx_memcpy(conf, prev, sizeof(ngx_http_index_conf_t));
+            ngx_memcpy(conf, prev, sizeof(ngx_http_index_loc_conf_t));
             return NGX_CONF_OK;
         }
 
@@ -408,8 +408,8 @@ static char *ngx_http_index_merge_conf(n
         conf->max_index_len = prev->max_index_len;
     }
 
-    if (conf->cache == NULL) {
-        conf->cache = prev->cache;
+    if (conf->index_cache == NULL) {
+        conf->index_cache = prev->index_cache;
     }
 
     return NGX_CONF_OK;
@@ -421,7 +421,7 @@ static char *ngx_http_index_merge_conf(n
 static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
                                       void *conf)
 {
-    ngx_http_index_conf_t *ilcf = conf;
+    ngx_http_index_loc_conf_t *ilcf = conf;
 
     int         i;
     ngx_str_t  *index, *value;
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -4,13 +4,28 @@
 #include <ngx_http.h>
 
 
-static int ngx_http_static_handler(ngx_http_request_t *r);
-static int ngx_http_static_init(ngx_cycle_t *cycle);
+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_cycle_t *cycle);
 
 
 static ngx_command_t  ngx_http_static_commands[] = {
 
-    ngx_null_command
+    { 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 },
+
+      ngx_null_command
 };
 
 
@@ -24,8 +39,8 @@ ngx_http_module_t  ngx_http_static_modul
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
     
-    NULL,                                  /* create location configuration */
-    NULL                                   /* merge location configuration */
+    ngx_http_static_create_loc_conf,       /* create location configuration */
+    ngx_http_static_merge_loc_conf         /* merge location configuration */
 };  
 
 
@@ -39,86 +54,149 @@ ngx_module_t  ngx_http_static_module = {
 };
 
 
-ngx_int_t ngx_http_static_translate_handler(ngx_http_request_t *r)
+static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r)
 {
-    char                      *location, *last, *path;
-    uint32_t                   crc;
-    ngx_int_t                  rc, level;
-    ngx_str_t                  name;
-    ngx_err_t                  err;
-    ngx_http_cache_t          *cache;
-    ngx_http_cache_conf_t     *ccf;
-    ngx_http_core_loc_conf_t  *clcf;
+    char                        *last;
+    uint32_t                     file_crc, redirect_crc;
+    ngx_fd_t                     fd;
+    ngx_int_t                    rc, level;
+    ngx_str_t                    name, location;
+    ngx_err_t                    err;
+    ngx_log_t                   *log;
+    ngx_hunk_t                  *h;
+    ngx_chain_t                  out;
+    ngx_file_info_t              fi;
+    ngx_http_cache_t            *file, *redirect;
+    ngx_http_cleanup_t          *file_cleanup, *redirect_cleanup;
+    ngx_http_log_ctx_t          *ctx;
+    ngx_http_core_loc_conf_t    *clcf;
+    ngx_http_static_loc_conf_t  *slcf;
+
+    if (r->uri.data[r->uri.len - 1] == '/') {
+        return NGX_DECLINED;
+    }
 
     if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
         return NGX_HTTP_NOT_ALLOWED;
     }
 
+    rc = ngx_http_discard_body(r);
+
+    if (rc != NGX_OK) {
+        return rc;
+    }
+
+    /*
+     * there is a valid cached open file, i.e by index handler,
+     * and it must be already registered in r->cleanup
+     */
+
+    if (r->cache && r->cache->valid) {
+        return ngx_http_send_cached(r);
+    }
+
+    log = r->connection->log;
+
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-
-    if (r->uri.data[r->uri.len - 1] == '/') {
-
-        /* there is no index handler */
-
-        if (!(path = ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len))) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
+    /*
+     * make a file name
+     * 2 bytes is for a trailing '/' in a possible redirect and for '\0'
+     */
 
-        ngx_cpystrn(ngx_cpymem(path, clcf->doc_root.data, clcf->doc_root.len),
-                    r->uri.data, r->uri.len + 1);
-
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "directory index of \"%s\" is forbidden", path);
-
-        return NGX_HTTP_FORBIDDEN;
-    }
-
-
-    /* "+ 2" is for a trailing '/' in a possible redirect and '\0' */
     ngx_test_null(name.data,
                   ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len + 2),
                   NGX_HTTP_INTERNAL_SERVER_ERROR);
 
-    location = ngx_cpymem(name.data, clcf->doc_root.data, clcf->doc_root.len);
-    last = ngx_cpystrn(location, r->uri.data, r->uri.len + 1);
+    location.data = ngx_cpymem(name.data, clcf->doc_root.data,
+                               clcf->doc_root.len);
+    last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1);
+    name.len = last - name.data;
+    location.len = last - location.data + 1;
 
-    ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ data);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                   "http filename: \"%s\"", name.data);
 
 
-    if (r->cache == NULL) {
+    /* allocate cleanups */
 
-        /* look up an open files cache */
+    if (!(file_cleanup = ngx_push_array(&r->cleanup))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+    file_cleanup->valid = 0;
 
-        ccf = ngx_http_get_module_loc_conf(r, ngx_http_cache_module);
-
-        if (ccf->open_files) {
-            cache = ngx_http_cache_get(ccf->open_files, &name, &crc);
-
-            ngx_log_debug(r->connection->log, "cache get: %x" _ cache);
+    slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
+    if (slcf->redirect_cache) {
+        if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+        redirect_cleanup->valid = 0;
 
-            if (cache
-                && ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)
-                    || ccf->open_files->update
-                                          >= ngx_cached_time - cache->updated))
-            {
-                r->cache = cache;
-                r->content_handler = ngx_http_static_handler;
+    } else {
+        redirect_cleanup = NULL;
+    }
+
+
+    /* look up an open files cache */
 
-                return NGX_OK;
-            }
+    if (clcf->open_files) {
+        file = ngx_http_cache_get(clcf->open_files, file_cleanup,
+                                  &name, &file_crc);
 
-        } else {
-            cache = NULL;
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                       "http open file cache get: " PTR_FMT, file);
+
+        if (file && file->valid) {
+            r->cache = file;
+            return ngx_http_send_cached(r);
         }
 
     } else {
-        cache = r->cache;
+        file = NULL;
     }
 
 
+    /* look up an redirect cache */
+
+    if (slcf->redirect_cache) {
+        redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup,
+                                      &name, &redirect_crc);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                       "http redirect cache get: " PTR_FMT, redirect);
+
+        if (redirect && redirect->valid) {
+
+            /*
+             * We do not copy a cached value so the cache entry is locked
+             * until the end of the request.  In a single threaded model
+             * the redirected request should complete before other event
+             * will be processed.  In a multithreaded model this locking
+             * should keep more popular redirects in cache.
+             */
+
+            if (!(r->headers_out.location =
+                   ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
+            {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            r->headers_out.location->value = redirect->data.value;
+
+            return NGX_HTTP_MOVED_PERMANENTLY;
+        }
+
+    } else {
+        redirect = NULL;
+    }
+
+
+    /* open file */
+
 #if (WIN9X)
 
+    /* TODO: redirect cache */
+
     if (ngx_win32_version < NGX_WIN_NT) {
 
         /*
@@ -127,9 +205,9 @@ ngx_int_t ngx_http_static_translate_hand
          * so we need to check its type before the opening
          */
 
-        if (ngx_file_info(name.data, &r->file.info) == NGX_FILE_ERROR) {
+        if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) {
             err = ngx_errno;
-            ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
+            ngx_log_error(NGX_LOG_ERR, log, err,
                           ngx_file_info_n " \"%s\" failed", name.data);
 
             if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
@@ -143,8 +221,8 @@ ngx_int_t ngx_http_static_translate_hand
             }
         }
 
-        if (ngx_is_dir(&r->file.info)) {
-            ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ name.data);
+        if (ngx_is_dir(&fi)) {
+            ngx_log_debug(log, "HTTP DIR: '%s'" _ name.data);
 
             if (!(r->headers_out.location =
                    ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
@@ -154,8 +232,6 @@ ngx_int_t ngx_http_static_translate_hand
 
             *last++ = '/';
             *last = '\0';
-            r->headers_out.location->key.len = 8;
-            r->headers_out.location->key.data = "Location" ;
             r->headers_out.location->value.len = last - location;
             r->headers_out.location->value.data = location;
 
@@ -166,12 +242,9 @@ ngx_int_t ngx_http_static_translate_hand
 #endif
 
 
-    if (r->file.fd == NGX_INVALID_FILE) {
-        r->file.fd = ngx_open_file(r->file.name.data,
-                                   NGX_FILE_RDONLY, NGX_FILE_OPEN);
-    }
+    fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
-    if (r->file.fd == NGX_INVALID_FILE) {
+    if (fd == NGX_INVALID_FILE) {
         err = ngx_errno;
 
         if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
@@ -187,60 +260,37 @@ ngx_int_t ngx_http_static_translate_hand
             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        ngx_log_error(level, r->connection->log, ngx_errno,
-                      ngx_open_file_n " \"%s\" failed", r->file.name.data);
+        ngx_log_error(level, log, err,
+                      ngx_open_file_n " \"%s\" failed", name.data);
 
         return rc;
     }
 
-ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd);
-
-    if (!r->file.info_valid) {
-        if (ngx_fd_info(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_fd_info_n " \"%s\" failed", r->file.name.data);
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);
 
-            if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed",
-                              r->file.name.data);
-            }
+    if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+                      ngx_fd_info_n " \"%s\" failed", name.data);
 
-            r->file.fd = NGX_INVALID_FILE;
-
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", name.data);
         }
 
-        r->file.info_valid = 1;
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (ccf->open_files) {
-        if (cache == NULL) {
-            cache = ngx_http_cache_alloc(ccf->open_files, &r->file.name, crc,
-                                         r->connection->log);
+    if (ngx_is_dir(&fi)) {
+
+        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", name.data);
         }
 
-ngx_log_debug(r->connection->log, "cache alloc: %x" _ cache);
-
-        if (cache) {
-            cache->fd = r->file.fd;
-            cache->data.size = ngx_file_size(&r->file.info);
-            cache->accessed = ngx_time();
-            cache->last_modified = ngx_file_mtime(&r->file.info);
-            cache->updated = ngx_time();
-        }
-    }
-
-    if (ngx_is_dir(&r->file.info)) {
-ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
-
-        if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed", r->file.name.data);
-        }
-
-        r->file.fd = NGX_INVALID_FILE;
-        r->file.info_valid = 0;
+        *last++ = '/';
+        *last = '\0';
 
         if (!(r->headers_out.location =
                    ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
@@ -248,153 +298,152 @@ ngx_log_debug(r->connection->log, "HTTP 
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        *last++ = '/';
-        *last = '\0';
-#if 0
-        r->headers_out.location->key.len = 8;
-        r->headers_out.location->key.data = "Location" ;
-#endif
-        r->headers_out.location->value.len = last - location;
-        r->headers_out.location->value.data = location;
+        r->headers_out.location->value = location;
+
+        if (slcf->redirect_cache) {
+            if (redirect) {
+                if (location.len == redirect->data.value.len
+                    && ngx_memcmp(redirect->data.value.data, location.data,
+                                                            location.len) == 0)
+                {
+                    redirect->accessed = ngx_cached_time;
+                    redirect->updated = ngx_cached_time;
+
+                    /*
+                     * we can unlock the cache entry because
+                     * we have the local copy anyway
+                     */
+
+                    ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
+                    redirect_cleanup->valid = 0;
+
+                    return NGX_HTTP_MOVED_PERMANENTLY;
+                }
+            }
+
+            location.len++;
+            redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect,
+                                            redirect_cleanup,
+                                            &name, redirect_crc,
+                                            &location, log);
+            location.len--;
+
+            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                           "http redirect cache alloc: " PTR_FMT, redirect);
+
+            if (redirect) {
+                redirect->fd = NGX_INVALID_FILE;
+                redirect->accessed = ngx_cached_time;
+                redirect->last_modified = 0;
+                redirect->updated = ngx_cached_time;
+                redirect->valid = 1;
+                redirect->memory = 1;
+                ngx_http_cache_unlock(slcf->redirect_cache, redirect, log);
+                redirect_cleanup->valid = 0;
+            }
+
+        }
 
         return NGX_HTTP_MOVED_PERMANENTLY;
     }
 
 #if !(WIN32) /* the not regular files are probably Unix specific */
 
-    if (!ngx_is_file(&r->file.info)) {
-        ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                      "%s is not a regular file", r->file.name.data);
+    if (!ngx_is_file(&fi)) {
+        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+                      "%s is not a regular file", name.data);
 
-        if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                          ngx_close_file_n " %s failed", r->file.name.data);
+        if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", name.data);
+        }
 
         return NGX_HTTP_NOT_FOUND;
     }
 
 #endif
 
-    r->content_handler = ngx_http_static_handler;
+
+    if (clcf->open_files) {
+
+#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
+
+        if (file && file->uniq == ngx_file_uniq(&fi)) {
+            if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                              ngx_close_file_n " \"%s\" failed", name.data);
+            }
+            file->accessed = ngx_cached_time;
+            file->updated = ngx_cached_time;
+            file->valid = 1;
+            r->cache = file;
+
+            return ngx_http_send_cached(r);
+
+        } else {
+            if (file) {
+                ngx_http_cache_unlock(clcf->open_files, file, log);
+                file = NULL;
+            }
 
-    return NGX_OK;
-}
+            file = ngx_http_cache_alloc(clcf->open_files, file,
+                                        file_cleanup,
+                                        &name, file_crc, NULL, log);
+            if (file) {
+                file->uniq = ngx_file_uniq(&fi);
+            }
+        }
+
+#else
+        file = ngx_http_cache_alloc(clcf->open_files, file,
+                                    file_cleanup,
+                                    &name, file_crc, NULL, log);
+#endif
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                       "http open file cache alloc: " PTR_FMT, file);
+
+        if (file) {
+            file->fd = fd;
+            file->data.size = ngx_file_size(&fi);
+            file->accessed = ngx_cached_time;
+            file->last_modified = ngx_file_mtime(&fi);
+            file->updated = ngx_cached_time;
+            file->valid = 1;
+            r->cache = file;
+        }
+
+        return ngx_http_send_cached(r);
+    }
 
 
-static int ngx_http_static_handler(ngx_http_request_t *r)
-{
-    int                        rc, key, i;
-    ngx_log_e                  level;
-    ngx_err_t                  err;
-    ngx_hunk_t                *h;
-    ngx_chain_t                out;
-    ngx_http_type_t           *type;
-    ngx_http_cleanup_t        *cleanup;
-    ngx_http_log_ctx_t        *ctx;
-    ngx_http_core_loc_conf_t  *clcf;
-
-    rc = ngx_http_discard_body(r);
-
-    if (rc != NGX_OK) {
-        return rc;
-    }
-
-    ctx = r->connection->log->data;
+    ctx = log->data;
     ctx->action = "sending response to client";
 
-    if (!(cleanup = ngx_push_array(&r->cleanup))) {
+    file_cleanup->data.file.fd = fd;
+    file_cleanup->data.file.name = name.data;
+    file_cleanup->valid = 1;
+    file_cleanup->cache = 0;
+
+    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);
+
+    if (ngx_http_set_content_type(r) != NGX_OK) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (r->file.fd == NGX_INVALID_FILE) {
-        r->file.fd = ngx_open_file(r->file.name.data,
-                                   NGX_FILE_RDONLY, NGX_FILE_OPEN);
-
-        if (r->file.fd == NGX_INVALID_FILE) {
-            err = ngx_errno;
-
-            if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
-                level = NGX_LOG_ERR;
-                rc = NGX_HTTP_NOT_FOUND;
-
-            } else {
-                level = NGX_LOG_CRIT;
-                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
-            }
-
-            ngx_log_error(level, r->connection->log, ngx_errno,
-                          ngx_open_file_n " %s failed", r->file.name.data);
-            return rc;
-        }
-    }
 
-    cleanup->data.file.fd = r->file.fd;
-    cleanup->data.file.name = r->file.name.data;
-    cleanup->cache = 0;
-
-    if (!r->file.info_valid) {
-        if (ngx_fd_info(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_fd_info_n " %s failed", r->file.name.data);
-
-            if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                              ngx_close_file_n " %s failed", r->file.name.data);
+    /* we need to allocate all before the header would be sent */
 
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        r->file.info_valid = 1;
-    }
-
-    r->headers_out.status = NGX_HTTP_OK;
-    r->headers_out.content_length_n = ngx_file_size(&r->file.info);
-    r->headers_out.last_modified_time = ngx_file_mtime(&r->file.info);
-
-    if (!(r->headers_out.content_type =
-                   ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
-    {
+    if (!(h = ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)))) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    r->headers_out.content_type->key.len = 0;
-    r->headers_out.content_type->key.data = NULL;
-    r->headers_out.content_type->value.len = 0;
-    r->headers_out.content_type->value.data = NULL;
-
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-    if (r->exten.len) {
-        ngx_http_types_hash_key(key, r->exten);
-
-        type = (ngx_http_type_t *) clcf->types[key].elts;
-        for (i = 0; i < clcf->types[key].nelts; i++) {
-            if (r->exten.len != type[i].exten.len) {
-                continue;
-            }
-
-            if (ngx_strcasecmp(r->exten.data, type[i].exten.data) == 0) {
-                r->headers_out.content_type->value.len = type[i].type.len;
-                r->headers_out.content_type->value.data = type[i].type.data;
-
-                break;
-            }
-        }
+    if (!(h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (r->headers_out.content_type->value.len == 0) {
-        r->headers_out.content_type->value.len = clcf->default_type.len;
-        r->headers_out.content_type->value.data = clcf->default_type.data;
-    }
-
-    /* we need to allocate all before the header would be sent */
-
-    ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
-                  NGX_HTTP_INTERNAL_SERVER_ERROR);
-
-    ngx_test_null(h->file, ngx_pcalloc(r->pool, sizeof(ngx_file_t)),
-                  NGX_HTTP_INTERNAL_SERVER_ERROR);
-
     rc = ngx_http_send_header(r);
 
     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
@@ -404,10 +453,10 @@ static int ngx_http_static_handler(ngx_h
     h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
 
     h->file_pos = 0;
-    h->file_last = ngx_file_size(&r->file.info);
+    h->file_last = ngx_file_size(&fi);
 
-    h->file->fd = r->file.fd;
-    h->file->log = r->connection->log;
+    h->file->fd = fd;
+    h->file->log = log;
 
     out.hunk = h;
     out.next = NULL;
@@ -416,7 +465,35 @@ static int ngx_http_static_handler(ngx_h
 }
 
 
-static int ngx_http_static_init(ngx_cycle_t *cycle)
+static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_static_loc_conf_t  *conf;
+
+    if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t)))) {
+        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_cycle_t *cycle)
 {
     ngx_http_handler_pt        *h;
     ngx_http_conf_ctx_t        *ctx;
@@ -425,11 +502,12 @@ static int ngx_http_static_init(ngx_cycl
     ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
     cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
     
-    ngx_test_null(h, ngx_push_array(
-                             &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
-                  NGX_ERROR);
-    *h = ngx_http_static_translate_handler;
+    h = ngx_push_array(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
+    if (h == NULL) {
+        return NGX_ERROR;
+    }
+
+    *h = ngx_http_static_handler;
 
     return NGX_OK;
 }
-
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -51,6 +51,7 @@ static char *ngx_http_block(ngx_conf_t *
     ngx_listening_t             *ls;
     ngx_http_module_t           *module;
     ngx_conf_t                   pcf;
+    ngx_http_handler_pt         *h;
     ngx_http_conf_ctx_t         *ctx;
     ngx_http_in_port_t          *in_port, *inport;
     ngx_http_in_addr_t          *in_addr, *inaddr;
@@ -219,17 +220,24 @@ static char *ngx_http_block(ngx_conf_t *
     ngx_init_array(cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
                    cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
                    NGX_CONF_ERROR);
-
     cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK;
-    cmcf->phases[NGX_HTTP_REWRITE_PHASE].post_handler =
-                                                 ngx_http_find_location_config;
 
 
-    ngx_init_array(cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers,
+    ngx_init_array(cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers,
+                   cf->cycle->pool, 1, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+    cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].type = NGX_OK;
+
+    ngx_test_null(h, ngx_push_array(
+                           &cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers),
+                  NGX_CONF_ERROR);
+    *h = ngx_http_find_location_config;
+
+
+    ngx_init_array(cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
                    cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
                    NGX_CONF_ERROR);
-
-    cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].type = NGX_OK;
+    cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK;
 
 
     /* create the lists of the ports, the addresses and the server names
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -7,6 +7,7 @@
 #include <ngx_garbage_collector.h>
 
 typedef struct ngx_http_request_s  ngx_http_request_t;
+typedef struct ngx_http_cleanup_s  ngx_http_cleanup_t;
 
 #include <ngx_http_cache.h>
 #include <ngx_http_request.h>
--- a/src/http/ngx_http_cache.c
+++ b/src/http/ngx_http_cache.c
@@ -13,13 +13,6 @@
 #endif
 
 
-static int ngx_crc(char *data, size_t len);
-
-static void *ngx_http_cache_create_conf(ngx_conf_t *cf);
-static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
-                                          void *parent, void *child);
-
-
 static ngx_http_module_t  ngx_http_cache_module_ctx = {
     NULL,                                  /* pre conf */
 
@@ -29,8 +22,8 @@ static ngx_http_module_t  ngx_http_cache
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
 
-    ngx_http_cache_create_conf,            /* create location configuration */
-    ngx_http_core_merge_loc_conf           /* merge location configuration */
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
 };
 
 
@@ -44,6 +37,248 @@ ngx_module_t  ngx_http_cache_module = {
 };
 
 
+ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *hash,
+                                     ngx_http_cleanup_t *cleanup,
+                                     ngx_str_t *key, uint32_t *crc)
+{
+    ngx_uint_t         i;
+    ngx_http_cache_t  *c;
+
+    *crc = ngx_crc(key->data, key->len);
+
+    c = hash->elts + *crc % hash->hash * hash->nelts;
+
+    ngx_mutex_lock(&hash->mutex);
+
+    for (i = 0; i < hash->nelts; i++) {
+        if (c[i].crc == *crc
+            && c[i].key.len == key->len
+            && ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0)
+        {
+            c[i].refs++;
+            ngx_mutex_unlock(&hash->mutex);
+
+            if (c[i].notify) {
+                if (!(ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)) {
+                    c[i].valid = 0;
+                }
+
+            } else if (ngx_cached_time - c[i].updated >= hash->update) {
+                c[i].valid = 0;
+            }
+
+            if (cleanup) {
+                cleanup->data.cache.hash = hash;
+                cleanup->data.cache.cache = &c[i];
+                cleanup->valid = 1;
+                cleanup->cache = 1;
+            }
+
+            return &c[i];
+        }
+    }
+
+    ngx_mutex_unlock(&hash->mutex);
+
+    return NULL;
+}
+
+
+ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
+                                       ngx_http_cache_t *cache,
+                                       ngx_http_cleanup_t *cleanup,
+                                       ngx_str_t *key, uint32_t crc,
+                                       ngx_str_t *value, ngx_log_t *log)
+{
+    time_t             old;
+    ngx_uint_t         i;
+    ngx_http_cache_t  *c;
+
+    old = ngx_cached_time + 1;
+
+    c = hash->elts + crc % hash->hash * hash->nelts;
+
+    ngx_mutex_lock(&hash->mutex);
+
+    if (cache == NULL) {
+
+        /* allocate a new entry */
+
+        for (i = 0; i < hash->nelts; i++) {
+            if (c[i].refs > 0) {
+                /* a busy entry */
+                continue;
+            }
+
+            if (c[i].key.len == 0) {
+                /* a free entry is found */
+                cache = &c[i];
+                break;
+            }
+
+            /* looking for the oldest cache entry */
+
+            if (old > c[i].accessed) {
+
+                old = c[i].accessed;
+                cache = &c[i];
+            }
+        }
+
+        if (cache == NULL) {
+            ngx_mutex_unlock(&hash->mutex);
+            return NULL;
+        }
+
+        ngx_http_cache_free(cache, key, value, log);
+
+        if (cache->key.data == NULL) {
+            cache->key.data = ngx_alloc(key->len, log);
+            if (cache->key.data == NULL) {
+                ngx_http_cache_free(cache, NULL, NULL, log);
+                ngx_mutex_unlock(&hash->mutex);
+                return NULL;
+            }
+        }
+
+        cache->key.len = key->len;
+        ngx_memcpy(cache->key.data, key->data, key->len);
+
+    } else if (value) {
+        ngx_http_cache_free(cache, key, value, log);
+    }
+
+    if (value) {
+        if (cache->data.value.data == NULL) {
+            cache->data.value.data = ngx_alloc(value->len, log);
+            if (cache->data.value.data == NULL) {
+                ngx_http_cache_free(cache, NULL, NULL, log);
+                ngx_mutex_unlock(&hash->mutex);
+                return NULL;
+            }
+        }
+
+        cache->data.value.len = value->len;
+        ngx_memcpy(cache->data.value.data, value->data, value->len);
+    }
+
+    cache->crc = crc;
+    cache->key.len = key->len;
+
+    cache->refs = 1;
+    cache->count = 0;
+
+    cache->valid = 1;
+    cache->deleted = 0;
+    cache->memory = 0;
+    cache->mmap = 0;
+    cache->notify = 0;
+
+    if (cleanup) {
+        cleanup->data.cache.hash = hash;
+        cleanup->data.cache.cache = cache;
+        cleanup->valid = 1;
+        cleanup->cache = 1;
+    }
+
+    ngx_mutex_unlock(&hash->mutex);
+
+    return cache;
+}
+
+
+void ngx_http_cache_free(ngx_http_cache_t *cache,
+                         ngx_str_t *key, ngx_str_t *value, ngx_log_t *log)
+{
+    if (cache->memory) {
+        if (cache->data.value.data
+            && (value == NULL || value->len > cache->data.value.len))
+        {
+            ngx_free(cache->data.value.data);
+            cache->data.value.data = NULL;
+        }
+    }
+
+    /* TODO: mmap */
+
+    cache->data.value.len = 0;
+
+    if (cache->fd != NGX_INVALID_FILE) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+                       "http cache close fd: %d", cache->fd);
+
+        if (ngx_close_file(cache->fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed",
+                          cache->key.data);
+        }
+
+        cache->fd = NGX_INVALID_FILE;
+    }
+
+    if (cache->key.data && (key == NULL || key->len > cache->key.len)) {
+        ngx_free(cache->key.data);
+        cache->key.data = NULL;
+    }
+
+    cache->key.len = 0;
+
+    cache->refs = 0;
+}
+
+
+void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
+                           ngx_http_cache_t *cache, ngx_log_t *log)
+{
+    ngx_mutex_lock(&hash->mutex);
+
+    cache->refs--;
+
+    if (cache->refs == 0 && cache->deleted) {
+        ngx_http_cache_free(cache, NULL, NULL, log);
+    }
+
+    ngx_mutex_unlock(&hash->mutex);
+}
+
+
+#if 0
+
+ngx_add_file_event(ngx_fd_t, ngx_event_handler_pt *handler, void *data)
+{
+    ngx_event_t  *ev;
+
+    ev = &ngx_cycle->read_events[fd];
+    ngx_memzero(ev, sizeof(ngx_event_t);
+
+    ev->data = data;
+    ev->event_handler = handler;
+
+    return ngx_add_event(ev, NGX_VNODE_EVENT, 0);
+}
+
+
+void ngx_http_cache_invalidate(ngx_event_t *ev)
+{
+    ngx_http_cache_ctx_t  *ctx;
+
+    ctx = ev->data;
+
+    ngx_http_cache_lock(&ctx->hash->mutex);
+
+    if (ctx->cache->refs == 0)
+        ngx_http_cache_free(ctx->cache, NULL, NULL, ctx->log);
+
+    } else {
+        ctx->cache->deleted = 1;
+    }
+
+    ngx_http_cache_unlock(&ctx->hash->mutex);
+}
+
+#endif
+
 
 int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx)
 {
@@ -80,125 +315,6 @@ ngx_log_debug(r->connection->log, "FILE:
 }
 
 
-ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache,
-                                     ngx_str_t *key, uint32_t *crc)
-{
-    ngx_uint_t         i;
-    ngx_http_cache_t  *c;
-
-    *crc = ngx_crc(key->data, key->len);
-
-    c = cache->elts + *crc % cache->hash * cache->nelts;
-
-    ngx_mutex_lock(&cache->mutex);
-
-    for (i = 0; i < cache->nelts; i++) {
-        if (c[i].crc == *crc
-            && c[i].key.len == key->len
-            && ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0)
-        {
-            c[i].refs++;
-            ngx_mutex_unlock(&cache->mutex);
-            return &c[i];
-        }
-    }
-
-    ngx_mutex_unlock(&cache->mutex);
-
-    return NULL;
-}
-
-
-ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *cache,
-                                       ngx_str_t *key, uint32_t crc,
-                                       ngx_log_t *log)
-{
-    time_t             old;
-    ngx_uint_t         i;
-    ngx_http_cache_t  *c, *found;
-
-    old = ngx_cached_time + 1;
-    found = NULL;
-
-    c = cache->elts + crc % cache->hash * cache->nelts;
-
-    ngx_mutex_lock(&cache->mutex);
-
-    for (i = 0; i < cache->nelts; i++) {
-        if (c[i].refs > 0) {
-            /* a busy entry */
-            continue;
-        }
-
-        if (c[i].key.data == NULL) {
-            /* a free entry is found */
-            found = &c[i];
-            break;
-        }
-
-        /* looking for the oldest cache entry */
-
-        if (old > c[i].accessed) {
-
-            old = c[i].accessed;
-            found = &c[i];
-        }
-    }
-
-    if (found) {
-        if (found->key.data) {
-            if (key->len > found->key.len) {
-                ngx_free(found->key.data);
-                found->key.data = NULL;
-            }
-        }
-
-        if (found->key.data == NULL) {
-            found->key.data = ngx_alloc(key->len, log);
-            if (found->key.data == NULL) {
-                ngx_mutex_unlock(&cache->mutex);
-                return NULL;
-            }
-        }
-
-        ngx_memcpy(found->key.data, key->data, key->len);
-
-        found->crc = crc;
-        found->key.len = key->len;
-        found->refs = 1;
-        found->count = 0;
-        found->deleted = 0;
-    }
-
-    ngx_mutex_unlock(&cache->mutex);
-
-    return found;
-}
-
-
-void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
-                           ngx_http_cache_t *cache, ngx_log_t *log)
-{
-    ngx_mutex_lock(&hash->mutex);
-
-    cache->refs--;
-
-    if (cache->refs == 0 && cache->deleted) {
-ngx_log_debug(log, "CLOSE FILE: %d" _ cache->fd);
-        if (cache->fd != NGX_INVALID_FILE) {
-            if (ngx_close_file(cache->fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed",
-                              cache->key.data);
-            }
-        }
-        cache->key.data = NULL;
-    }
-
-    ngx_mutex_unlock(&hash->mutex);
-}
-
-
 int ngx_http_cache_open_file(ngx_http_cache_ctx_t *ctx, ngx_file_uniq_t uniq)
 {
     ssize_t                   n;
@@ -331,6 +447,57 @@ int ngx_http_cache_update_file(ngx_http_
 }
 
 
+/* TODO: currently fd only */
+
+ngx_int_t ngx_http_send_cached(ngx_http_request_t *r)
+{
+    ngx_int_t            rc;
+    ngx_hunk_t          *h;
+    ngx_chain_t          out;
+    ngx_http_log_ctx_t  *ctx;
+
+    ctx = r->connection->log->data;
+    ctx->action = "sending response to client";
+
+    r->headers_out.status = NGX_HTTP_OK;
+    r->headers_out.content_length_n = r->cache->data.size;
+    r->headers_out.last_modified_time = r->cache->last_modified;
+
+    if (ngx_http_set_content_type(r) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    /* we need to allocate all before the header would be sent */
+
+    if (!(h = ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (!(h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    rc = ngx_http_send_header(r);
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
+    }
+
+    h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
+
+    h->file_pos = 0;
+    h->file_last = ngx_file_size(&r->file.info);
+
+    h->file->fd = r->cache->fd;
+    h->file->log = r->connection->log;
+
+    out.hunk = h;
+    out.next = NULL;
+
+    return ngx_http_output_filter(r, &out);
+}
+
+
 int ngx_garbage_collector_http_cache_handler(ngx_gc_t *gc, ngx_str_t *name,
                                              ngx_dir_t *dir)
 {
@@ -375,85 +542,13 @@ int ngx_garbage_collector_http_cache_han
 }
 
 
-/* 32-bit crc16 */
-
-static int ngx_crc(char *data, size_t len)
-{
-    uint32_t  sum;
-
-    for (sum = 0; len; len--) {
-        /*
-         * gcc 2.95.2 x86 and icc 7.1.006 compile that operator
-         *                                into the single rol opcode.
-         * msvc 6.0sp2 compiles it into four opcodes.
-         */
-        sum = sum >> 1 | sum << 31;
-
-        sum += *data++;
-    }
-
-    return sum;
-}
-
-
-static void *ngx_http_cache_create_conf(ngx_conf_t *cf)
-{
-    ngx_http_cache_conf_t  *conf;
-
-    if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_conf_t)))) {
-        return NGX_CONF_ERROR;
-    }
-
-    return conf;
-}
-
-
-static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
-                                          void *parent, void *child)
-{
-    ngx_http_cache_conf_t *prev = parent;
-    ngx_http_cache_conf_t *conf = child;
-
-    if (conf->open_files == NULL) {
-        conf->open_files = prev->open_files;
-    }
-
-#if 0
-    if (conf->open_files == NULL) {
-        if (prev->open_files) {
-            conf->open_files = prev->open_files;
-
-        } else {
-            conf->open_files = ngx_pcalloc(cf->pool,
-                                           sizeof(ngx_http_cache_hash_t));
-            if (conf->open_files == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            conf->open_files->hash = NGX_HTTP_CACHE_HASH;
-            conf->open_files->nelts = NGX_HTTP_CACHE_NELTS;
-
-            conf->open_files->elts = ngx_pcalloc(cf->pool,
-                                                 NGX_HTTP_CACHE_HASH
-                                                 * NGX_HTTP_CACHE_NELTS
-                                                 * sizeof(ngx_http_cache_t));
-            if (conf->open_files->elts == NULL) {
-                return NGX_CONF_ERROR;
-            }
-        }
-    }
-#endif
-
-    return NGX_CONF_OK;
-}
-
-
 char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
 
-    ngx_int_t              i, dup, invalid;
+    ngx_int_t              i, j, dup, invalid;
     ngx_str_t              *value, line;
+    ngx_http_cache_t       *c;
     ngx_http_cache_hash_t  *ch, **chp;
 
     chp = (ngx_http_cache_hash_t **) (p + cmd->offset);
@@ -566,5 +661,13 @@ char *ngx_http_set_cache_slot(ngx_conf_t
         return NGX_CONF_ERROR;
     }
 
+    for (i = 0; i < (ngx_int_t) ch->hash; i++) {
+        c = ch->elts + i * ch->nelts;
+
+        for (j = 0; j < (ngx_int_t) ch->nelts; j++) {
+            c[j].fd = NGX_INVALID_FILE;
+        }
+    }
+
     return NGX_CONF_OK;
 }
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -7,22 +7,37 @@
 #include <ngx_http.h>
 
 
+/*
+ * The 7 uses before an allocation.
+ * We can use maximum 7 bits, i.e up to the 127 uses.
+ */
+#define NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS  3
+
 typedef struct {
-    uint32_t       crc;
-    ngx_str_t      key;
-    time_t         accessed;
+    uint32_t         crc;
+    ngx_str_t        key;
+    time_t           accessed;
+
+    unsigned         refs:20;    /* 1048576 references */
 
-    unsigned       refs:20;    /* 1048576 references */
-    unsigned       count:2;    /* lazy allocation: the 4 uses */
-    unsigned       deleted:1;
+    unsigned         count:NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS;
 
-    ngx_fd_t       fd;
-    time_t         last_modified;
-    time_t         updated;
+    unsigned         valid:1;
+    unsigned         deleted:1;
+    unsigned         memory:1;
+    unsigned         mmap:1;
+    unsigned         notify:1;
+
+    ngx_fd_t         fd;
+#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
+    ngx_file_uniq_t  uniq;       /* no needed with kqueue */
+#endif
+    time_t           last_modified;
+    time_t           updated;
 
     union {
-        off_t      size;
-        ngx_str_t  value;
+        off_t        size;
+        ngx_str_t    value;
     } data;
 } ngx_http_cache_t;
 
@@ -69,29 +84,32 @@ typedef struct {
 } ngx_http_cache_ctx_t;
 
 
-typedef struct {
-    ngx_http_cache_hash_t    *open_files;
-} ngx_http_cache_conf_t;
-
-
 
 #define NGX_HTTP_CACHE_STALE     1
 #define NGX_HTTP_CACHE_AGED      2
 #define NGX_HTTP_CACHE_THE_SAME  3
 
 
+ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache,
+                                     ngx_http_cleanup_t *cleanup,
+                                     ngx_str_t *key, uint32_t *crc);
+
+ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
+                                       ngx_http_cache_t *cache,
+                                       ngx_http_cleanup_t *cleanup,
+                                       ngx_str_t *key, uint32_t crc,
+                                       ngx_str_t *value, ngx_log_t *log);
+void ngx_http_cache_free(ngx_http_cache_t *cache,
+                         ngx_str_t *key, ngx_str_t *value, ngx_log_t *log);
+void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
+                           ngx_http_cache_t *cache, ngx_log_t *log);
+
 int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
 int ngx_http_cache_open_file(ngx_http_cache_ctx_t *ctx, ngx_file_uniq_t uniq);
 int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx,
                                ngx_str_t *temp_file);
 
-ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache,
-                                     ngx_str_t *key, uint32_t *crc);
-ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *cache,
-                                       ngx_str_t *key, uint32_t crc,
-                                       ngx_log_t *log);
-void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
-                           ngx_http_cache_t *cache, ngx_log_t *log);
+int ngx_http_send_cached(ngx_http_request_t *r);
 
 
 int ngx_garbage_collector_http_cache_handler(ngx_gc_t *gc, ngx_str_t *name,
@@ -100,8 +118,4 @@ int ngx_garbage_collector_http_cache_han
 char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
-extern ngx_module_t  ngx_http_cache_module;
-
-
-
 #endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -38,173 +38,180 @@ static ngx_conf_post_t  ngx_http_lowat_p
 
 static ngx_command_t  ngx_http_core_commands[] = {
 
-    {ngx_string("server"),
-     NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-     ngx_server_block,
-     0,
-     0,
-     NULL},
+    { ngx_string("server"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+      ngx_server_block,
+      0,
+      0,
+      NULL },
 
-    {ngx_string("connection_pool_size"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_size_slot,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     offsetof(ngx_http_core_srv_conf_t, connection_pool_size),
-     NULL},
+    { ngx_string("connection_pool_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_core_srv_conf_t, connection_pool_size),
+      NULL },
 
-    {ngx_string("post_accept_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     offsetof(ngx_http_core_srv_conf_t, post_accept_timeout),
-     NULL},
+    { ngx_string("post_accept_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_core_srv_conf_t, post_accept_timeout),
+      NULL },
 
-    {ngx_string("request_pool_size"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_size_slot,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     offsetof(ngx_http_core_srv_conf_t, request_pool_size),
-     NULL},
+    { ngx_string("request_pool_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_core_srv_conf_t, request_pool_size),
+      NULL },
 
-    {ngx_string("client_header_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     offsetof(ngx_http_core_srv_conf_t, client_header_timeout),
-     NULL},
+    { ngx_string("client_header_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_core_srv_conf_t, client_header_timeout),
+      NULL },
 
-    {ngx_string("client_header_buffer_size"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_size_slot,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     offsetof(ngx_http_core_srv_conf_t, client_header_buffer_size),
-     NULL},
+    { ngx_string("client_header_buffer_size"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_core_srv_conf_t, client_header_buffer_size),
+      NULL },
 
-    {ngx_string("large_client_header"),
-     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, large_client_header),
-     NULL},
+    { ngx_string("large_client_header"),
+      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, large_client_header),
+      NULL },
 
-    {ngx_string("location"),
-     NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
-     ngx_location_block,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     0,
-     NULL},
+    { ngx_string("location"),
+      NGX_HTTP_SRV_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
+      ngx_location_block,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      0,
+      NULL },
 
-    {ngx_string("listen"),
+    { ngx_string("listen"),
 #if 0
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
 #else
-     NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
+      NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
 #endif
-     ngx_set_listen,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     0,
-     NULL},
+      ngx_set_listen,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      0,
+      NULL },
 
-    {ngx_string("server_name"),
-     NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
-     ngx_set_server_name,
-     NGX_HTTP_SRV_CONF_OFFSET,
-     0,
-     NULL},
+    { ngx_string("server_name"),
+      NGX_HTTP_SRV_CONF|NGX_CONF_1MORE,
+      ngx_set_server_name,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      0,
+      NULL },
 
-    {ngx_string("types"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
-                                         |NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-     ngx_types_block,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     0,
-     NULL},
+    { ngx_string("types"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF
+                                          |NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+      ngx_types_block,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
 
-    {ngx_string("default_type"),
-     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_core_loc_conf_t, default_type),
-     NULL},
+    { ngx_string("default_type"),
+      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_core_loc_conf_t, default_type),
+      NULL },
 
-    {ngx_string("root"),
-     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_core_loc_conf_t, doc_root),
-     NULL},
+    { ngx_string("root"),
+      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_core_loc_conf_t, doc_root),
+      NULL },
 
-    {ngx_string("client_body_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_core_loc_conf_t, client_body_timeout),
-     NULL},
+    { ngx_string("client_body_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, client_body_timeout),
+      NULL },
 
-    {ngx_string("sendfile"),
-     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, sendfile),
-     NULL},
+    { ngx_string("sendfile"),
+      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, sendfile),
+      NULL },
 
-    {ngx_string("send_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_core_loc_conf_t, send_timeout),
-     NULL},
+    { ngx_string("send_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, send_timeout),
+      NULL },
 
-    {ngx_string("send_lowat"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_size_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_core_loc_conf_t, send_lowat),
-     &ngx_http_lowat_post},
+    { ngx_string("send_lowat"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, send_lowat),
+      &ngx_http_lowat_post },
 
-    {ngx_string("keepalive_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_core_loc_conf_t, keepalive_timeout),
-     NULL},
+    { ngx_string("keepalive_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, keepalive_timeout),
+      NULL },
 
-    {ngx_string("lingering_time"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_core_loc_conf_t, lingering_time),
-     NULL},
+    { ngx_string("lingering_time"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, lingering_time),
+      NULL },
 
-    {ngx_string("lingering_timeout"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_msec_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_core_loc_conf_t, lingering_timeout),
-     NULL},
+    { ngx_string("lingering_timeout"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, lingering_timeout),
+      NULL },
 
-    {ngx_string("msie_padding"),
-     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, msie_padding),
-     NULL},
+    { ngx_string("msie_padding"),
+      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, msie_padding),
+      NULL },
+
+    { ngx_string("error_page"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
+      ngx_set_error_page,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
 
-    {ngx_string("error_page"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
-     ngx_set_error_page,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     0,
-     NULL},
+    { ngx_string("error_log"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_set_error_log,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
 
-    {ngx_string("error_log"),
-     NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_set_error_log,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     0,
-     NULL},
+    { 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_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, open_files),
+      NULL },
 
-    ngx_null_command
+      ngx_null_command
 };
 
 
@@ -301,15 +308,22 @@ static void ngx_http_phase_event_handler
 
 static void ngx_http_run_phases(ngx_http_request_t *r)
 {
-    int                         rc;
+    char                       *path;
+    ngx_int_t                   rc;
     ngx_http_handler_pt        *h;
+    ngx_http_core_loc_conf_t   *clcf;
     ngx_http_core_main_conf_t  *cmcf;
 
     cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
 
-    rc = NGX_DECLINED;
+    for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) {
 
-    for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) {
+        if (r->phase == NGX_HTTP_CONTENT_PHASE && r->content_handler) {
+            r->connection->write->event_handler = ngx_http_empty_handler;
+            rc = r->content_handler(r);
+            ngx_http_finalize_request(r, rc);
+            return;
+        }
 
         h = cmcf->phases[r->phase].handlers.elts;
         for (r->phase_handler = cmcf->phases[r->phase].handlers.nelts - 1;
@@ -319,6 +333,12 @@ static void ngx_http_run_phases(ngx_http
             rc = h[r->phase_handler](r);
 
             if (rc == NGX_DONE) {
+
+                /*
+                 * we should never use r here because 
+                 * it could point to already freed data
+                 */
+
                 return;
             }
 
@@ -330,38 +350,45 @@ static void ngx_http_run_phases(ngx_http
                 return;
             }
 
-            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+            if (rc >= NGX_HTTP_SPECIAL_RESPONSE || rc == NGX_ERROR) {
                 ngx_http_finalize_request(r, rc);
                 return;
             }
 
+            if (rc == NGX_OK && r->phase == NGX_HTTP_CONTENT_PHASE) {
+                ngx_http_finalize_request(r, 0);
+                return;
+            }
+
             if (rc == NGX_OK && cmcf->phases[r->phase].type == NGX_OK) {
                 break;
             }
         }
-
-        if (cmcf->phases[r->phase].post_handler) {
-            rc = cmcf->phases[r->phase].post_handler(r);
-
-            if (rc == NGX_AGAIN) {
-                return;
-            }
-
-            if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-                ngx_http_finalize_request(r, rc);
-                return;
-            }
-        }
     }
 
-    if (r->content_handler) {
-        r->connection->write->event_handler = ngx_http_empty_handler;
-        rc = r->content_handler(r);
-        ngx_http_finalize_request(r, rc);
+
+    if (r->uri.data[r->uri.len - 1] == '/') {
+
+        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+        if (!(path = ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len))) {
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
+        }
+    
+        ngx_cpystrn(ngx_cpymem(path, clcf->doc_root.data, clcf->doc_root.len),
+                    r->uri.data, r->uri.len + 1);
+    
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "directory index of \"%s\" is forbidden", path);
+
+        ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
         return;
     }
 
-    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found");
+
+    ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
     return;
 }
 
@@ -500,6 +527,55 @@ ngx_log_debug(r->connection->log, "trans
 }
 
 
+ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r)
+{
+    uint32_t                   key;
+    ngx_int_t                  i;
+    ngx_http_type_t           *type;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (!(r->headers_out.content_type =
+                   ngx_http_add_header(&r->headers_out, ngx_http_headers_out)))
+    {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    r->headers_out.content_type->key.len = 0;
+    r->headers_out.content_type->key.data = NULL;
+    r->headers_out.content_type->value.len = 0;
+    r->headers_out.content_type->value.data = NULL;
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (r->exten.len) {
+#if 0
+        key = ngx_crc(r->exten.data, r->exten.key);
+#endif
+        ngx_http_types_hash_key(key, r->exten);
+
+        type = clcf->types[key].elts;
+        for (i = 0; i < clcf->types[key].nelts; i++) {
+            if (r->exten.len != type[i].exten.len) {
+                continue;
+            }
+
+            if (ngx_memcmp(r->exten.data, type[i].exten.data, r->exten.len)
+                                                                           == 0)
+            {
+                r->headers_out.content_type->value = type[i].type;
+                break;
+            }
+        }
+    }
+
+    if (r->headers_out.content_type->value.len == 0) {
+        r->headers_out.content_type->value = clcf->default_type;
+    }
+
+    return NGX_OK;
+}
+
+
 int ngx_http_send_header(ngx_http_request_t *r)
 {
     if (r->main) {
@@ -870,7 +946,7 @@ static char *ngx_set_type(ngx_conf_t *cf
 
     int               i, key;
     ngx_str_t        *args;
-    ngx_http_type_t  *t;
+    ngx_http_type_t  *type;
 
     if (lcf->types == NULL) {
         ngx_test_null(lcf->types,
@@ -889,11 +965,9 @@ static char *ngx_set_type(ngx_conf_t *cf
     for (i = 1; i < cf->args->nelts; i++) {
         ngx_http_types_hash_key(key, args[i]);
 
-        ngx_test_null(t, ngx_push_array(&lcf->types[key]), NGX_CONF_ERROR);
-        t->exten.len = args[i].len;
-        t->exten.data = args[i].data;
-        t->type.len = args[0].len;
-        t->type.data = args[0].data;
+        ngx_test_null(type, ngx_push_array(&lcf->types[key]), NGX_CONF_ERROR);
+        type->exten = args[i];
+        type->type = args[0];
     }
 
     return NGX_CONF_OK;
@@ -1124,6 +1198,10 @@ static char *ngx_http_core_merge_loc_con
 
     ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
 
+    if (conf->open_files == NULL) {
+        conf->open_files = prev->open_files;
+    }
+
     return NGX_CONF_OK;
 }
 
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -17,15 +17,19 @@ typedef struct {
 } ngx_http_listen_t;
 
 
+typedef enum {
+    NGX_HTTP_REWRITE_PHASE = 0,
+    NGX_HTTP_FIND_CONFIG_PHASE,
+    NGX_HTTP_CONTENT_PHASE,
+    NGX_HTTP_LAST_PHASE
+} ngx_http_phases;
+
+
 typedef struct {
     ngx_array_t          handlers;
     int                  type;                /* NGX_OK, NGX_DECLINED */
-    ngx_http_handler_pt  post_handler;
 } ngx_http_phase_t;
 
-#define NGX_HTTP_REWRITE_PHASE    0
-#define NGX_HTTP_TRANSLATE_PHASE  1
-#define NGX_HTTP_LAST_PHASE       2
 
 typedef struct {
     ngx_array_t       servers;         /* array of ngx_http_core_srv_conf_t */
@@ -128,36 +132,17 @@ typedef struct {
     int           msie_padding;            /* msie_padding */
     ngx_array_t  *error_pages;             /* error_page */
 
+    ngx_http_cache_hash_t  *open_files;
+
     ngx_regex_t  *regex;
 
     unsigned      exact_match:1;
-
     unsigned      auto_redirect:1;
 
     ngx_log_t    *err_log;
 } ngx_http_core_loc_conf_t;
 
 
-
-
-#if 0
-typedef struct {
-    int dummy;
-} ngx_http_core_conf_t;
-#endif
-
-
-#if 0
-#define ngx_http_set_loc_handler(conf_ctx, ngx_http_handler)                  \
-    {                                                                         \
-        ngx_http_conf_ctx_t       *cx = conf_ctx;                             \
-        ngx_http_core_loc_conf_t  *lcf;                                       \
-        lcf = cx->loc_conf[ngx_http_core_module_ctx.index];                   \
-        lcf->handler = ngx_http_handler;                                      \
-    }
-#endif
-
-
 extern ngx_http_module_t  ngx_http_core_module_ctx;
 extern ngx_module_t  ngx_http_core_module;
 
@@ -168,6 +153,8 @@ extern int ngx_http_max_module;
 int ngx_http_find_location_config(ngx_http_request_t *r);
 int ngx_http_core_translate_handler(ngx_http_request_t *r);
 
+ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
+
 int ngx_http_internal_redirect(ngx_http_request_t *r,
                                ngx_str_t *uri, ngx_str_t *args);
 int ngx_http_error(ngx_http_request_t *r, int error);
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -642,6 +642,7 @@ int ngx_http_parse_complex_uri(ngx_http_
     state = sw_usual;
     p = r->uri_start;
     u = r->uri.data;
+    r->uri_ext = NULL;
 
     ch = *p++;
 
@@ -654,6 +655,7 @@ ngx_log_debug(r->connection->log, "S: %d
         case sw_usual:
             switch(ch) {
             case '/':
+                r->uri_ext = NULL;
                 state = sw_slash;
                 *u++ = ch;
                 break;
@@ -661,6 +663,8 @@ ngx_log_debug(r->connection->log, "S: %d
                 quoted_state = state;
                 state = sw_quoted;
                 break;
+            case '.':
+                r->uri_ext = u + 1;
             default:
                 *u++ = ch;
                 break;
@@ -811,5 +815,17 @@ ngx_log_debug(r->connection->log, "S: %d
     r->uri.len = u - r->uri.data;
     r->uri.data[r->uri.len] = '\0';
 
+    if (r->uri_ext) {
+        r->exten.len = u - r->uri_ext;
+
+        if (!(r->exten.data = ngx_palloc(r->pool, r->exten.len + 1))) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
+    }
+
+    r->uri_ext = NULL;
+
     return NGX_OK;
 }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -359,6 +359,21 @@ static void ngx_http_process_request_lin
         if (r->complex_uri) {
             rc = ngx_http_parse_complex_uri(r);
 
+            if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+                ngx_http_close_request(r, rc);
+                ngx_http_close_connection(c);
+                return;
+            }
+
+            if (rc != NGX_OK) {
+                r->request_line.len = r->request_end - r->request_start;
+                r->request_line.data = r->request_start;
+                r->request_line.data[r->request_line.len] = '\0';
+
+                ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
+                return;
+            }
+
         } else {
             ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
         }
@@ -389,16 +404,6 @@ static void ngx_http_process_request_lin
         }
 
 
-        if (rc != NGX_OK) {
-            /*
-             * we check ngx_http_parse_complex_uri() result here to log
-             * the request line
-             */
-            ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
-            return;
-        }
-
-
         if (r->uri_ext) {
 
             /* copy URI extention */
@@ -536,7 +541,8 @@ static void ngx_http_process_request_hea
     c = rev->data;
     r = c->data;
 
-    ngx_log_debug(rev->log, "http process request header line");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
+                   "http process request header line");
 
     if (rev->timedout) {
         ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
@@ -1387,13 +1393,16 @@ int ngx_http_send_last(ngx_http_request_
 void ngx_http_close_request(ngx_http_request_t *r, int error)
 {
     ngx_int_t            i;
+    ngx_log_t           *log;
     ngx_http_log_ctx_t  *ctx;
     ngx_http_cleanup_t  *cleanup;
 
-    ngx_log_debug(r->connection->log, "close http request");
+    log = r->connection->log;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http close request");
 
     if (r->pool == NULL) {
-        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+        ngx_log_error(NGX_LOG_ALERT, log, 0,
                       "http request already closed");
         return;
     }
@@ -1406,29 +1415,36 @@ void ngx_http_close_request(ngx_http_req
 
     cleanup = r->cleanup.elts;
     for (i = 0; i < r->cleanup.nelts; i++) {
-        if (cleanup[i].cache) {
-            ngx_http_cache_unlock(cleanup[i].data.cache.hash,
-                                  cleanup[i].data.cache.cache,
-                                  r->connection->log);
+        if (!cleanup[i].valid) {
             continue;
         }
 
+        if (cleanup[i].cache) {
+            ngx_http_cache_unlock(cleanup[i].data.cache.hash,
+                                  cleanup[i].data.cache.cache, log);
+            continue;
+        }
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http cleanup fd: %d",
+                       cleanup[i].data.file.fd);
+
         if (ngx_close_file(cleanup[i].data.file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                           ngx_close_file_n " \"%s\" failed",
                           cleanup[i].data.file.name);
         }
     }
 
+    /* STUB */
     if (r->file.fd != NGX_INVALID_FILE) {
         if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                           ngx_close_file_n " \"%s\" failed", r->file.name.data);
         }
     }
 
     /* ctx->url was allocated from r->pool */
-    ctx = r->connection->log->data;
+    ctx = log->data;
     ctx->url = NULL;
 
     ngx_destroy_pool(r->pool);
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -144,7 +144,7 @@ typedef struct {
 } ngx_http_headers_out_t;
 
 
-typedef struct {
+struct ngx_http_cleanup_s {
     union {
         struct {
             ngx_fd_t                 fd;
@@ -157,8 +157,9 @@ typedef struct {
         } cache;
     } data;
 
+    unsigned                         valid:1;
     unsigned                         cache:1;
-} ngx_http_cleanup_t;
+};
 
 
 typedef int (*ngx_http_handler_pt)(ngx_http_request_t *r);
@@ -194,8 +195,6 @@ struct ngx_http_request_s {
     ngx_str_t            args;
     ngx_str_t            exten;
     ngx_str_t            unparsed_uri;
-    ngx_str_t            path;
-    int                  path_allocated;
 
     ngx_http_request_t  *main;
 
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -5,16 +5,16 @@
 
 
 /*
- * sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 and 1176
- * or in 6 packets: 5x1460 and 892.  Besides although sendfile() allows
- * to pass the header and the trailer it never sends the header or the trailer
- * with the part of the file in one packet.  So we use TCP_NOPUSH (similar
- * to Linux's TCP_CORK) to postpone the sending - it not only sends the header
- * and the first part of the file in one packet but also sends 4K pages
- * in the full packets.
+ * FreeBSD's sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460
+ * and 1176 or in 6 packets: 5x1460 and 892.  Besides although sendfile()
+ * allows to pass the header and the trailer it never sends the header or
+ * the trailer with the part of the file in one packet.  So we use TCP_NOPUSH
+ * (similar to Linux's TCP_CORK) to postpone the sending - it not only sends
+ * the header and the first part of the file in one packet but also sends
+ * 4K pages in the full packets.
  *
- * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush the pending
- * data that less than MSS so the data can be sent with 5 second delay.
+ * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending
+ * data that less than MSS so that data can be sent with 5 second delay.
  * We do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used
  * for non-keepalive HTTP connections.
  */
--- a/src/os/unix/ngx_linux_sendfile_chain.c
+++ b/src/os/unix/ngx_linux_sendfile_chain.c
@@ -6,10 +6,9 @@
 
 /*
  * On Linux up to 2.4.21 sendfile() (syscall #187) works with 32-bit
- * offsets only and the including <sys/sendfile.h> breaks building
- * if off_t is 64 bit wide.  So we use own sendfile() definition where
- * offset paramter is int32_t.  It allows to use sendfile() with
- * the file parts below 2G.
+ * offsets only and the including <sys/sendfile.h> breaks building if
+ * off_t is 64 bit wide.  So we use own sendfile() definition where offset
+ * parameter is int32_t and use sendfile() with the file parts below 2G.
  *
  * Linux 2.4.21 has a new sendfile64() syscall #239.
  */