changeset 69:e43f406e4525

nginx-0.0.1-2003-03-20-19:09:44 import
author Igor Sysoev <igor@sysoev.ru>
date Thu, 20 Mar 2003 16:09:44 +0000
parents d549fdc17d7e
children e320bf51c4e3
files src/core/ngx_core.h src/core/ngx_string.c src/core/ngx_string.h src/event/modules/ngx_devpoll_module.c src/event/modules/ngx_iocp_module.c src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_poll_module.c src/event/modules/ngx_select_module.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_acceptex.c src/event/ngx_event_recv.c src/http/modules/ngx_http_event_proxy_handler.c src/http/modules/ngx_http_event_proxy_handler.h src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_log_handler.c src/http/modules/ngx_http_static_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_config.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_event.c src/http/ngx_http_header_filter.c src/http/ngx_http_output_filter.c src/http/ngx_http_special_response.c src/http/ngx_http_write_filter.c
diffstat 27 files changed, 1335 insertions(+), 707 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -6,7 +6,7 @@
 #define  NGX_ERROR      -1
 #define  NGX_DONE        NGX_ERROR
 #define  NGX_AGAIN      -2
-#define  NGX_WAITING    -3
+#define  NGX_BUSY       -3
 #define  NGX_DECLINED   -4
 #define  NGX_ALERT      -5
 
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1,5 +1,6 @@
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_string.h>
 
 
@@ -19,3 +20,72 @@ char *ngx_cpystrn(char *dst, char *src, 
 
     return dst;
 }
+
+
+int ngx_atoi(char *line, size_t n)
+{
+    int  value;
+
+    for (value = 0; n--; line++) {
+       if (*line < '0' || *line > '9') {
+           return NGX_ERROR;
+       }
+
+       value = value * 10 + (*line - '0');
+    }
+
+    return value;
+}
+
+
+#if 0
+char *ngx_psprintf(ngx_pool_t *p, const char *fmt, ...)
+{
+    va_list    args;
+
+    va_start(args, fmt);
+
+    while (*fmt) {
+         switch(*fmt++) {
+         case '%':
+             switch(*fmt++) {
+             case 's':
+                 s = va_arg(args, char *);
+                 n += ngx_strlen(s);
+                 break;
+
+             default:
+                 n++;
+         }
+         default:
+             n++;
+         }
+    }
+
+    str = ngx_palloc(p, n);
+
+    va_start(args, fmt);
+
+    for (i = 0; i < n; i++) {
+         switch(*fmt++) {
+         case '%':
+             switch(*fmt++) {
+             case 's':
+                 s = va_arg(args, char *);
+                 while (str[i++] = s);
+                 break;
+
+             default:
+                 n++;
+         }
+         default:
+             str[i] = *fmt;
+         }
+    }
+
+    len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args);
+
+    va_end(args);
+
+}
+#endif
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -49,6 +49,7 @@ typedef struct {
 #define ngx_cpymem(dst, src, n)   memcpy(dst, src, n) + n
 
 char *ngx_cpystrn(char *dst, char *src, size_t n);
+int ngx_atoi(char *line, size_t n);
 
 
 #endif /* _NGX_STRING_H_INCLUDED_ */
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -236,6 +236,7 @@ int ngx_devpoll_process_events(ngx_log_t
     if ((int) timer != INFTIM) {
         gettimeofday(&tv, NULL);
         delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
+        ngx_event_expire_timers(delta);
 
     } else {
         if (events == 0) {
@@ -305,9 +306,5 @@ int ngx_devpoll_process_events(ngx_log_t
         }
     }
 
-    if ((int) timer != INFTIM) {
-        ngx_event_expire_timers(delta);
-    }
-
     return NGX_OK;
 }
--- a/src/event/modules/ngx_iocp_module.c
+++ b/src/event/modules/ngx_iocp_module.c
@@ -110,6 +110,7 @@ int ngx_iocp_process_events(ngx_log_t *l
 
     if (timer != INFINITE) {
         delta = ngx_msec() - delta;
+        ngx_event_expire_timers(delta);
     }
 
     if (ovlp) {
@@ -118,6 +119,7 @@ int ngx_iocp_process_events(ngx_log_t *l
 ngx_log_debug(log, "iocp ev: %08x" _ ev);
 
         if (ev == e) {
+            /* it's not AcceptEx() completion */
             ev->ready = 1;
             ev->available = bytes;
         }
@@ -129,9 +131,5 @@ ngx_log_debug(log, "iocp ev: %08x" _ ev-
         }
     }
 
-    if (timer != INFINITE) {
-        ngx_event_expire_timers(delta);
-    }
-
     return NGX_OK;
 }
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -110,6 +110,13 @@ int ngx_kqueue_add_event(ngx_event_t *ev
     ev->active = 1;
     ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1: 0;
 
+    /* The event addition or change should be always passed to a kernel
+       because there can be case when event was passed to a kernel then
+       added again to the change_list and then deleted from the change_list
+       by ngx_kqueue_del_event() so the first event still remains in a kernel */
+
+#if 0
+
     if (nchanges > 0
         && ev->index < nchanges
         && change_list[ev->index].udata == ev)
@@ -118,12 +125,17 @@ int ngx_kqueue_add_event(ngx_event_t *ev
         ngx_connection_t *c = (ngx_connection_t *) ev->data;
         ngx_log_debug(ev->log, "kqueue add event: %d: ft:%d" _ c->fd _ event);
 #endif
+
+        /* if the event is still not passed to a kernel we change it */
+
         change_list[ev->index].filter = event;
         change_list[ev->index].flags = flags;
 
         return NGX_OK;
     }
 
+#endif
+
     return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
 }
 
@@ -142,6 +154,9 @@ int ngx_kqueue_del_event(ngx_event_t *ev
         ngx_connection_t *c = (ngx_connection_t *) ev->data;
         ngx_log_debug(ev->log, "kqueue del event: %d: ft:%d" _ c->fd _ event);
 #endif
+
+        /* if the event is still not passed to a kernel we will not pass it */
+
         if (ev->index < --nchanges) {
             e = (ngx_event_t *) change_list[nchanges].udata;
             change_list[ev->index] = change_list[nchanges];
@@ -151,6 +166,9 @@ int ngx_kqueue_del_event(ngx_event_t *ev
         return NGX_OK;
     }
 
+    /* when a socket is closed kqueue automatically deletes its filters 
+       so we do not need to delete a event explicity before a socket closing */
+
     if (flags & NGX_CLOSE_EVENT) {
         return NGX_OK;
     }
@@ -257,6 +275,11 @@ int ngx_kqueue_process_events(ngx_log_t 
         gettimeofday(&tv, NULL);
         delta = tv.tv_sec * 1000 + tv.tv_usec / 1000 - delta;
 
+        /* Expired timers must be deleted before the events processing
+           because the new timers can be added during the processing */
+
+        ngx_event_expire_timers(delta);
+
     } else {
         if (events == 0) {
             ngx_log_error(NGX_LOG_ALERT, log, 0,
@@ -295,6 +318,9 @@ int ngx_kqueue_process_events(ngx_log_t 
 
         ev = (ngx_event_t *) event_list[i].udata;
 
+        /* It's a stale event from a socket
+           that was just closed in this iteration */
+
         if (!ev->active) {
            continue;
         }
@@ -303,6 +329,29 @@ int ngx_kqueue_process_events(ngx_log_t 
 
         case EVFILT_READ:
         case EVFILT_WRITE:
+
+            if (ev->first) {
+                if (nchanges > 0
+                    && ev->index < nchanges
+                    && change_list[ev->index].udata == ev) {
+
+                    /* It's a stale event from a socket that was just closed
+                       in this iteration and during processing another socket
+                       was opened with the same number by accept() or socket()
+                       and its event has been added the event to the change_list
+                       but has not been passed to a kernel.  Nevertheless
+                       there's small chance that ngx_kqueue_set_event() has
+                       flushed the new event if the change_list was filled up.
+                       In this very rare case we would get EAGAIN while
+                       a reading or a writing */
+
+                    continue;
+
+                } else {
+                    ev->first = 0;
+                }
+            }
+ 
             ev->available = event_list[i].data;
 
             if (event_list[i].flags & EV_EOF) {
@@ -332,9 +381,5 @@ int ngx_kqueue_process_events(ngx_log_t 
         }
     }
 
-    if (timer) {
-        ngx_event_expire_timers(delta);
-    }
-
     return NGX_OK;
 }
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -175,6 +175,7 @@ int ngx_poll_process_events(ngx_log_t *l
 
     if ((int) timer != INFTIM) {
         delta = ngx_msec() - delta;
+        ngx_event_expire_timers(delta);
 
     } else {
         if (ready == 0) {
@@ -259,9 +260,5 @@ int ngx_poll_process_events(ngx_log_t *l
         ngx_log_error(NGX_LOG_ALERT, log, 0, "poll ready != events");
     }
 
-    if ((int) timer != INFTIM) {
-        ngx_event_expire_timers(delta);
-    }
-
     return NGX_OK;
 }
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -243,6 +243,7 @@ int ngx_select_process_events(ngx_log_t 
 
     if (timer) {
         delta = ngx_msec() - delta;
+        ngx_event_expire_timers(delta);
 
     } else {
         if (ready == 0) {
@@ -312,9 +313,5 @@ int ngx_select_process_events(ngx_log_t 
         ngx_log_error(NGX_LOG_ALERT, log, 0, "select ready != events");
     }
 
-    if (timer) {
-        ngx_event_expire_timers(delta);
-    }
-
     return NGX_OK;
 }
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -63,6 +63,7 @@ struct ngx_event_s {
 #endif
     unsigned         write:1;
 
+    unsigned         first:1;
     unsigned         active:1;
     unsigned         ready:1;
     unsigned         timedout:1;
@@ -179,8 +180,8 @@ typedef struct {
 #define NGX_USE_LEVEL_EVENT     0x00010000
 
 
-/* Event filter is deleted before closing file. Has no meaning
-   for select, poll, epoll.
+/* Event filter is deleted before closing file.
+   Has no meaning for select, poll, epoll.
 
    kqueue:     kqueue deletes event filters for file that closed
                so we need only to delete filters in user-level batch array
@@ -193,16 +194,24 @@ typedef struct {
 #define NGX_READ_EVENT     EVFILT_READ
 #define NGX_WRITE_EVENT    EVFILT_WRITE
 
+#define NGX_ENABLE_EVENT   EV_ENABLE
+#define NGX_DISABLE_EVENT  EV_DISABLE
+
+/* NGX_CLOSE_EVENT is the module flag and it would not go into a kernel
+   so we need to choose the value that would not interfere with any existent
+   and future flags. kqueue has such values - EV_FLAG1, EV_EOF and EV_ERROR.
+   They are reserved and cleared on a kernel entrance */
+#undef  NGX_CLOSE_EVENT
+#define NGX_CLOSE_EVENT    EV_FLAG1
+
 #define NGX_LEVEL_EVENT    0
 #define NGX_ONESHOT_EVENT  EV_ONESHOT
+#define NGX_CLEAR_EVENT    EV_CLEAR
 
 #ifndef HAVE_CLEAR_EVENT
 #define HAVE_CLEAR_EVENT   1
 #endif
 
-#if (HAVE_CLEAR_EVENT)
-#define NGX_CLEAR_EVENT    EV_CLEAR
-#endif
 
 #elif (HAVE_POLL) || (HAVE_DEVPOLL)
 
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -117,6 +117,7 @@ int ngx_event_accept(ngx_event_t *ev)
         c->fd = s;
         c->unexpected_eof = 1;
         wev->write = 1;
+        rev->first = wev->first = 1;
 
 #if (HAVE_AIO_EVENT)
         if (!(ngx_event_flags & NGX_HAVE_AIO_EVENT)) {
--- a/src/event/ngx_event_acceptex.c
+++ b/src/event/ngx_event_acceptex.c
@@ -104,6 +104,7 @@ int ngx_event_post_acceptex(ngx_listen_t
 
         c->unexpected_eof = 1;
         wev->write = 1;
+        rev->first = wev->first = 1;
 
         c->handler = ls->handler;
         rev->event_handler = ngx_event_acceptex;
--- a/src/event/ngx_event_recv.c
+++ b/src/event/ngx_event_recv.c
@@ -8,18 +8,13 @@
 
 ssize_t ngx_event_recv_core(ngx_connection_t *c, char *buf, size_t size)
 {
-    int                n;
-    ngx_err_t          err;
-    ngx_event_t       *ev;
+    ssize_t       n;
+    ngx_err_t     err;
+    ngx_event_t  *ev;
 
     ev = c->read;
 
-    if (ev->timedout) {
-        ngx_set_socket_errno(NGX_ETIMEDOUT);
-        ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, "recv() failed");
-        return NGX_ERROR;
-    }
-
+/* DEBUG */
 #if (HAVE_KQUEUE)
     if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
         ngx_log_debug(c->log, "ngx_event_recv: eof:%d, avail:%d, err:%d" _
@@ -30,54 +25,32 @@ ssize_t ngx_event_recv_core(ngx_connecti
 #if (USE_KQUEUE)
 
     if (ev->eof && ev->available == 0) {
-        if (ev->error) {
-            ngx_set_socket_errno(ev->error);
 
-            if (ev->error == NGX_ECONNRESET && ev->ignore_econnreset) {
-                return 0;
-            }
-
-            ngx_log_error(NGX_LOG_ERR, c->log, ev->error,
-                          "recv() failed");
-            return NGX_ERROR;
+        if (ev->error == 0) {
+            return 0;
         }
 
-        return 0;
-    }
-
-#elif (HAVE_KQUEUE)
-
-    if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
-        if (ev->eof && ev->available == 0) {
-            if (ev->error) {
-                ngx_set_socket_errno(ev->error);
+        ngx_set_socket_errno(ev->error);
+        err = ev->error;
+        n = -1;
 
-                if (ev->error == NGX_ECONNRESET && ev->ignore_econnreset) {
-                    return 0;
-                }
+    } else {
+        n = ngx_recv(c->fd, buf, size, 0);
 
-                ngx_log_error(NGX_LOG_ERR, c->log, ev->error,
-                              "recv() failed");
-                return NGX_ERROR;
-            }
-
-            return 0;
+        if (n == -1) {
+            err = ngx_socket_errno;
         }
     }
 
-#endif
-
-    n = ngx_recv(c->fd, buf, size, 0);
+    if (n == -1) {
+        ev->ready = 0;
 
-    if (n == -1) {
-        err = ngx_socket_errno;
-
-        if (ev->error == NGX_ECONNRESET && ev->ignore_econnreset) {
+        if (err == NGX_ECONNRESET && ev->ignore_econnreset) {
             return 0;
         }
 
         if (err == NGX_EAGAIN) {
-            ngx_log_error(NGX_LOG_INFO, c->log, err, "recv() returns EAGAIN");
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "recv() returned EAGAIN");
             return NGX_AGAIN;
         }
 
@@ -85,17 +58,90 @@ ssize_t ngx_event_recv_core(ngx_connecti
         return NGX_ERROR;
     }
 
-#if (USE_KQUEUE)
+    ev->available -= n;
+    if (ev->available == 0) {
+        ev->ready = 0;
+    }
 
-    ev->available -= n;
+    return n;
 
 #elif (HAVE_KQUEUE)
 
-    if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
-        ev->available -= n;
+    if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT)
+        && ev->eof && ev->available == 0) {
+
+        if (ev->error == 0) {
+            return 0;
+        }
+
+        ngx_set_socket_errno(ev->error);
+        err = ev->error;
+        n = -1;
+
+    } else {
+        n = ngx_recv(c->fd, buf, size, 0);
+ngx_log_debug(c->log, "ngx_event_recv: read:%d:%d" _ n _ size);
+
+        if (n == -1) {
+            err = ngx_socket_errno;
+        }
+    }
+
+    if (n == -1) {
+        ev->ready = 0;
+
+        if (err == NGX_ECONNRESET && ev->ignore_econnreset) {
+            return 0;
+        }
+
+        if (err == NGX_EAGAIN) {
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "recv() returned EAGAIN");
+            return NGX_AGAIN;
+        }
+
+        ngx_log_error(NGX_LOG_ERR, c->log, err, "recv() failed");
+        return NGX_ERROR;
     }
 
-#endif
+    if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
+        ev->available -= n;
+        if (ev->available == 0) {
+            ev->ready = 0;
+        }
+
+    } else if ((size_t) n < size) {
+        ev->ready = 0;
+    }
 
     return n;
+
+#else /* not kqueue */
+
+    n = ngx_recv(c->fd, buf, size, 0);
+
+    if (n == -1) {
+        err = ngx_socket_errno;
+
+        ev->ready = 0;
+
+        if (err == NGX_ECONNRESET && ev->ignore_econnreset) {
+            return 0;
+        }
+
+        if (err == NGX_EAGAIN) {
+            ngx_log_error(NGX_LOG_INFO, c->log, err, "recv() returned EAGAIN");
+            return NGX_AGAIN;
+        }
+
+        ngx_log_error(NGX_LOG_ERR, c->log, err, "recv() failed");
+        return NGX_ERROR;
+    }
+
+    if ((size_t) n < size) {
+        ev->ready = 0;
+    }
+
+    return n;
+
+#endif
 }
--- a/src/http/modules/ngx_http_event_proxy_handler.c
+++ b/src/http/modules/ngx_http_event_proxy_handler.c
@@ -14,47 +14,8 @@
 #include <ngx_http_event_proxy_handler.h>
 
 
-static ngx_command_t  ngx_http_proxy_commands[] = {
-
-    {ngx_string("proxy_large_header"),
-     NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
-     ngx_conf_set_flag_slot,
-     NGX_HTTP_LOC_CONF_OFFSET,
-     offsetof(ngx_http_proxy_loc_conf_t, large_header)},
-
-    {ngx_null_string, 0, NULL, 0, 0}
-};
-
-
-static ngx_http_module_t  ngx_http_proxy_module_ctx = {
-    NGX_HTTP_MODULE,
-
-    NULL,                                  /* create server config */
-    NULL,                                  /* init server config */
-    NULL,                                  /* create location config */
-    NULL,                                  /* merge location config */
-
-    NULL,                                  /* translate handler */
-
-    NULL,                                  /* output header filter */
-    NULL,                                  /* next output header filter */
-    NULL,                                  /* output body filter */
-    NULL                                   /* next output body filter */
-};
-
-
-ngx_module_t  ngx_http_proxy_module = {
-    0,                                     /* module index */
-    &ngx_http_proxy_module_ctx,            /* module context */
-    ngx_http_proxy_commands,               /* module directives */
-    NGX_HTTP_MODULE_TYPE,                  /* module type */
-    NULL                                   /* init module */
-};
-
-
-
 static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_request_t *r);
-static int ngx_http_proxy_connect(ngx_http_request_t *r,
+static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p,
                                   struct sockaddr_in *addr,
                                   char *addr_text);
 static int ngx_http_proxy_send_request(ngx_event_t *ev);
@@ -70,7 +31,48 @@ static int ngx_http_proxy_write_to_clien
 static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx);
 
 
-static char conn_close[] = "Connection: close" CRLF;
+static ngx_command_t  ngx_http_proxy_commands[] = {
+
+    {ngx_string("proxy_large_header"),
+     NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_conf_set_flag_slot,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     offsetof(ngx_http_proxy_loc_conf_t, large_header)},
+
+    {ngx_null_string, 0, NULL, 0, 0}
+};
+
+
+static ngx_http_module_t  ngx_http_proxy_module_ctx = {
+    NULL,                                  /* create server config */
+    NULL,                                  /* init server config */
+
+    NULL,                                  /* create location config */
+    NULL,                                  /* merge location config */
+
+    NULL                                   /* init filters */
+};
+
+
+ngx_module_t  ngx_http_proxy_module = {
+    0,                                     /* module index */
+    &ngx_http_proxy_module_ctx,            /* module context */
+    ngx_http_proxy_commands,               /* module directives */
+    NGX_HTTP_MODULE_TYPE,                  /* module type */
+    NULL                                   /* init module */
+};
+
+
+static ngx_str_t http_methods[] = {
+    ngx_string("GET "),
+    ngx_string("HEAD "),
+    ngx_string("POST ")
+};
+
+
+static char http_version[] = " HTTP/1.0" CRLF;
+static char host_header[] = "Host: ";
+static char conn_close_header[] = "Connection: close" CRLF;
 
 
 /* AF_INET only */
@@ -78,32 +80,57 @@ static char conn_close[] = "Connection: 
 
 int ngx_http_proxy_handler(ngx_http_request_t *r)
 {
-    struct sockaddr_in     addr;
-    ngx_chain_t           *chain;
-    ngx_http_proxy_ctx_t  *p;
+    struct sockaddr_in         addr;
+    ngx_chain_t               *chain;
+    ngx_http_proxy_ctx_t      *p;
+    ngx_http_log_ctx_t        *hcx;
+    ngx_http_proxy_log_ctx_t  *lcx;
 
     p = (ngx_http_proxy_ctx_t *)
-                         ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
+                             ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     if (p == NULL) {
-        ngx_http_create_ctx(r, p, ngx_http_proxy_module_ctx,
+        ngx_http_create_ctx(r, p, ngx_http_proxy_module,
                             sizeof(ngx_http_proxy_ctx_t),
                             NGX_HTTP_INTERNAL_SERVER_ERROR);
     }
 
+    p->request = r;
+
+    ngx_test_null(p->log, ngx_palloc(r->pool, sizeof(ngx_log_t)),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+    ngx_memcpy(p->log, r->connection->log, sizeof(ngx_log_t));
+    ngx_test_null(lcx, ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+    p->log->data = lcx;
+    hcx = r->connection->log->data;
+    lcx->client = hcx->client;
+
+    /*
+    if (!resolved) {
+        return ngx_dns_resolve(name, handler, p, r->pool, p->log);
+    }
+    */
+
     chain = ngx_http_proxy_create_request(r);
     if (chain == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
+    /* TODO: duplicate hunks and chain if there is backend farm */
     p->out = chain;
 
     ngx_memzero(&addr, sizeof(struct sockaddr_in));
     addr.sin_family = AF_INET;
+#if 0
     addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+#else
+    addr.sin_addr.s_addr = inet_addr("192.168.10.2");
+#endif
     addr.sin_port = htons(9000);
 
-    return ngx_http_proxy_connect(r, &addr, "connecting to 127.0.0.1:9000");
+    return ngx_http_proxy_connect(p, &addr, "connecting to 127.0.0.1:9000");
 }
 
 
@@ -125,7 +152,7 @@ static ngx_chain_t *ngx_http_proxy_creat
     /* TODO: Host length */
 
     /* "Connection: close\r\n" */
-    len += sizeof(conn_close) - 1;
+    len += sizeof(conn_close_header) - 1;
 
     header = (ngx_table_elt_t *) r->headers_in.headers->elts;
     for (i = 0; i < r->headers_in.headers->nelts; i++) {
@@ -146,16 +173,54 @@ static ngx_chain_t *ngx_http_proxy_creat
     ngx_test_null(hunk, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL);
     ngx_add_hunk_to_chain(chain, hunk, r->pool, NULL);
 
-    /* STUB: "method p->url HTTP/1.0" */
+#if 0
+
+    /* the request line */
+
+    ngx_memcpy(hunk->last, http_methods[p->method - 1].data,
+               http_methods[p->method - 1].len);
+    hunk->last += http_methods[p->method - 1].len;
+
+    ngx_memcpy(hunk->last, p->uri_start.data, p->uri_start.len);
+    hunk->last += p->uri_start.len;
+
+    ngx_memcpy(hunk->last, p->uri_rest.data, p->uri_rest.len);
+    hunk->last += p->uri_rest.len;
+
+    if (r->args) {
+        *(hunk->last++) = '?';
+        ngx_memcpy(hunk->last, r->uri_args.data, r->uri_args.len);
+        hunk->last += r->uri_args.len;
+    }
+
+    ngx_memcpy(hunk->last, http_version, sizeof(http_version) - 1);
+    hunk->last += sizeof(http_version) - 1;
+
+    /* the 'Host' header */
+
+    ngx_memcpy(hunk->last, host_header, sizeof(host_header) - 1);
+    hunk->last += sizeof(host_header) - 1;
+
+    ngx_memcpy(hunk->last, p->host.data, p->host.len);
+    hunk->last += p->host.len;
+
+    *(hunk->last++) = CR; *(hunk->last++) = LF;
+
+    /* the 'Connection: close' header */
+
+    ngx_memcpy(hunk->last, conn_close_header, sizeof(conn_close_header) - 1);
+    hunk->last += sizeof(conn_close_header) - 1;
+
+#else
 
     ngx_memcpy(hunk->last, r->request_line.data, r->request_line.len);
     hunk->last += r->request_line.len;
     *(hunk->last++) = CR; *(hunk->last++) = LF;
 
-    /* TODO: Host header */
+    ngx_memcpy(hunk->last, conn_close_header, sizeof(conn_close_header) - 1);
+    hunk->last += sizeof(conn_close_header) - 1;
 
-    ngx_memcpy(hunk->last, conn_close, sizeof(conn_close) - 1);
-    hunk->last += sizeof(conn_close) - 1;
+#endif
 
     for (i = 0; i < r->headers_in.headers->nelts; i++) {
         if (&header[i] == r->headers_in.host) {
@@ -190,7 +255,197 @@ static ngx_chain_t *ngx_http_proxy_creat
 }
 
 
-static int ngx_http_proxy_connect(ngx_http_request_t *r,
+#if 0
+
+client_read()
+    if (!ev->write) {
+        if error close upstream ?
+        else block it
+    }
+
+
+static int ngx_http_proxy_process_upstream(ngx_event_t *ev)
+{
+    again = 0;
+
+    do {
+
+        if (p->state_write_upstream_handler ==
+                                          ngx_http_proxy_connect_to_upstream) {
+            if (!get_cached_connection())
+                get_next_upstream(p);
+        }
+
+        if (ev->write) {
+
+            /* ngx_http_proxy_connect_to_upstream()
+               ngx_http_proxy_send_request() */
+
+            rc = p->state_write_upstream_handler(p);
+
+        } else {
+
+            /* ngx_http_proxy_read_response() */
+
+            rc = p->state_read_upstream_handler(p);
+        }
+
+        if (rc == NGX_BUSY || rc == NGX_AGAIN || rc == NGX_OK) {
+            return rc;
+        }
+
+        if (rc == NGX_ERROR) {
+            return ngx_http_proxy_finalize_request(p,
+                                               NGX_HTTP_INTERNAL_SERVER_ERROR);
+        }
+
+        /* This NGX_HTTP_INTERNAL_SERVER_ERROR is sent by an upstream */
+
+        if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT
+            || (rc == NGX_HTTP_INTERNAL_SERVER_ERROR && lcf->retry_500)
+        {
+            ngx_http_close_connection(ev);
+
+            if (p->upstream->amount > 1) {
+                /* Here is the race condition on SMP machine
+                   when the upstreams are shared between threads or processes
+                   but it's not serious */
+                p->upstream->upstreams[p->cur_upstream].fails++;
+            }
+
+            p->upstreams--;
+
+            if (p->upstreams == 0) {
+                return ngx_http_proxy_finalize_request(p, rc);
+            }
+
+            p->cur_upstream++;
+            if (p->cur_upstream > p->upstream->amount) {
+                p->cur_upstream = 0;
+            }
+
+            p->state_read_upstream_handler = ignore;
+            p->state_write_upstream_handler =
+                                            ngx_http_proxy_connect_to_upstream;
+            again = 1;
+        }
+
+        if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
+            ???
+        }
+
+    } while (again);
+
+    return NGX_BUSY;
+}
+
+
+static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p)
+{
+    ngx_socket_t         s;
+    ngx_connection_t    *c;
+    ngx_http_log_ctx_t  *lcx;
+
+    lcx = p->log->data;
+    lcx->action = "connecting to an upstream";
+    lcx->upstream = p->upstream.data;
+    p->log->handler = ngx_http_proxy_log_error;
+
+    s = ngx_socket(AF_INET, SOCK_STREAM, IPPROTO_IP, 0);
+    if (s == -1) {
+        ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno,
+                      ngx_socket_n " failed");
+        return NGX_ERROR;
+    }
+
+    if (lcf->rcvbuf) {
+        if (setsockopt(s, SOL_SOCKET, SO_RCVBUF,
+                       (const void *) &rcvbuf, sizeof(int)) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno,
+                          "setsockopt(SO_RCVBUF) failed");
+
+            if (ngx_close_socket(s) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno,
+                              ngx_close_socket_n " failed");
+            }
+
+            return NGX_ERROR;
+        }
+    }
+
+    if (ngx_nonblocking(s) == -1) {
+        ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno,
+                      ngx_nonblocking_n " failed");
+
+        if (ngx_close_socket(s) == -1) {
+            ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno,
+                          ngx_close_socket_n " failed");
+        }
+
+        return NGX_ERROR;
+    }
+
+    rc = connect(s, (struct sockaddr *) p->addr, sizeof(struct sockaddr_in));
+
+    if (rc == -1) {
+        err = ngx_socket_errno;
+        if (err != NGX_EINPROGRESS) {
+            ngx_log_error(NGX_LOG_CRIT, p->log, err, "connect() failed");
+
+            if (ngx_close_socket(s) == -1) {
+                ngx_log_error(NGX_LOG_ALERT, p->log, ngx_socket_errno,
+                              ngx_close_socket_n " failed");
+            }
+
+            return NGX_HTTP_BAD_GATEWAY;
+        }
+    }
+
+    c = &ngx_connections[s];
+    rev = &ngx_read_events[s];
+    wev = &ngx_write_events[s];
+
+    ngx_memzero(rev, sizeof(ngx_event_t));
+    ngx_memzero(wev, sizeof(ngx_event_t));
+    ngx_memzero(c, sizeof(ngx_connection_t));
+
+    rev->index = wev->index = NGX_INVALID_INDEX;
+
+    rev->data = wev->data = c;
+    c->read = rev;
+    c->write = wev;
+
+    rev->first = wev->first = 1;
+
+    c->data = p->request;
+    p->connection = c;
+
+    c->fd = s;
+
+    rev->log = wev->log = c->log = p->log;
+
+    ngx_test_null(c->pool, ngx_create_pool(lcf->conn_pool_size, p->log),
+                  NGX_ERROR);
+
+}
+
+#if 0
+connect_upstream()
+    get next upstream
+    init connect to upstream
+    if error return error
+    if ok send_request();
+    if inprogress p->state_handler = send_request, return busy
+
+send_request()
+    if timeout inc fail counter
+       p->state_handler = connect_upstream, return 504
+#endif
+
+#endif
+
+
+static int ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p,
                                   struct sockaddr_in *addr,
                                   char *addr_text)
 {
@@ -201,7 +456,7 @@ static int ngx_http_proxy_connect(ngx_ht
     ngx_connection_t    *c, *pc;
     ngx_http_log_ctx_t  *ctx;
 
-    c = r->connection;
+    c = p->request->connection;
     ctx = c->log->data;
     ctx->action = addr_text;
 
@@ -253,7 +508,7 @@ static int ngx_http_proxy_connect(ngx_ht
                               ngx_close_socket_n " failed");
             }
 
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            return NGX_HTTP_BAD_GATEWAY;
         }
     }
 
@@ -265,16 +520,21 @@ static int ngx_http_proxy_connect(ngx_ht
     ngx_memzero(wev, sizeof(ngx_event_t));
     ngx_memzero(pc, sizeof(ngx_connection_t));
 
+    rev->index = wev->index = NGX_INVALID_INDEX;
+
     rev->data = wev->data = pc;
     pc->read = rev;
     pc->write = wev;
 
-    pc->data = r;
+    pc->data = p->request;;
+    p->connection = pc;
 
     pc->fd = s;
     pc->servers = c->servers;
 
-    pc->log = rev->log = wev->log = c->log;
+    ngx_test_null(pc->log, ngx_palloc(c->pool, sizeof(ngx_log_t)), NGX_OK);
+    ngx_memcpy(pc->log, c->log, sizeof(ngx_log_t));
+    rev->log = wev->log = pc->log;
 
     ngx_test_null(pc->pool,
                   ngx_create_pool(/* STUB */ 1024 /**/, pc->log),
@@ -282,6 +542,8 @@ static int ngx_http_proxy_connect(ngx_ht
 
     wev->event_handler = ngx_http_proxy_send_request;
     rev->event_handler = ngx_http_proxy_init_response;
+    rev->close_handler = wev->close_handler = ngx_event_close_connection;
+
 
 #if (USE_KQUEUE)
 
@@ -314,18 +576,25 @@ static int ngx_http_proxy_connect(ngx_ht
 
     /* TODO: aio, iocp */
 
-    /* The connection is in a progress */
-    if (rc == -1) {
-        /* TODO: oneshot */
-        if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT) != NGX_OK) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
+    /* The connection has been established */
+    if (rc == 0) {
+        wev->write = 1;
+        wev->ready = 1;
+
+        return ngx_http_proxy_send_request(wev);
     }
 
-    wev->write = 1;
-    wev->ready = 1;
+    /* The connection is in a progress */
 
-    return ngx_http_proxy_send_request(wev);
+    /* TODO: oneshot */
+    if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    wev->timer_set = 1;
+    ngx_add_timer(wev, /* STUB: lcf->connect_timeout */ 10000);
+
+    return NGX_BUSY;
 }
 
 
@@ -339,7 +608,11 @@ static int ngx_http_proxy_send_request(n
     c = (ngx_connection_t *) ev->data;
     r = (ngx_http_request_t *) c->data;
     p = (ngx_http_proxy_ctx_t *)
-                         ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
+                             ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+    if (ev->timedout) {
+        return ngx_http_proxy_error(r, p, NGX_HTTP_GATEWAY_TIME_OUT);
+    }
 
     chain = ngx_write_chain(c, p->out, 0);
     if (chain == (ngx_chain_t *) -1) {
@@ -348,7 +621,7 @@ static int ngx_http_proxy_send_request(n
 
     p->out = chain;
 
-    return NGX_WAITING;
+    return NGX_BUSY;
 }
 
 
@@ -368,7 +641,7 @@ static int ngx_http_proxy_init_response(
     }
 
     p = (ngx_http_proxy_ctx_t *)
-                         ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
+                             ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     ngx_test_null(p->header_in,
                   ngx_create_temp_hunk(r->pool,
@@ -407,7 +680,7 @@ static int ngx_http_proxy_read_response_
     c = (ngx_connection_t *) ev->data;
     r = (ngx_http_request_t *) c->data;
     p = (ngx_http_proxy_ctx_t *)
-                         ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+                             ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     if (ev->timedout) {
         return ngx_http_proxy_error(r, p, NGX_HTTP_GATEWAY_TIME_OUT);
@@ -516,7 +789,7 @@ static int ngx_http_proxy_read_response_
         return ngx_http_proxy_read_response_body(ev);
     }
 
-    return NGX_WAITING;
+    return NGX_BUSY;
 }
 
 
@@ -575,7 +848,7 @@ static int ngx_http_proxy_read_response_
     c = (ngx_connection_t *) ev->data;
     r = (ngx_http_request_t *) c->data;
     p = (ngx_http_proxy_ctx_t *)
-                         ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
+                             ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     if (p->hunks.nelts > 0) {
         h = ((ngx_hunk_t **) p->hunks.elts)[p->hunks.nelts - 1];
@@ -631,7 +904,7 @@ static int ngx_http_proxy_read_response_
         ngx_log_debug(c->log, "READ:%d" _ n);
 
         if (n == NGX_AGAIN) {
-            return NGX_WAITING;
+            return NGX_BUSY;
         }
 
         if (n == NGX_ERROR) {
@@ -660,7 +933,7 @@ static int ngx_http_proxy_read_response_
         return ngx_http_proxy_write_to_client(c->write);
     }
 
-    /* STUB */ return NGX_WAITING;
+    /* STUB */ return NGX_BUSY;
 }
 
 
@@ -675,7 +948,7 @@ static int ngx_http_proxy_write_to_clien
     c = (ngx_connection_t *) ev->data;
     r = (ngx_http_request_t *) c->data;
     p = (ngx_http_proxy_ctx_t *)
-                         ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx);
+                             ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
     do {
         h = ((ngx_hunk_t **) p->hunks.elts)[p->hunk_n];
@@ -706,6 +979,17 @@ static int ngx_http_proxy_error(ngx_http
 }
 
 
+static size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
+{
+    ngx_http_proxy_log_ctx_t *lcx = (ngx_http_proxy_log_ctx_t *) data;
+
+    return ngx_snprintf(buf, len,
+                        " while %s, upstream: %s, client: %s, URL: %s",
+                        lcx->action, lcx->upstream, lcx->client, lcx->url);
+}
+
+
+
 static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx)
 {
     char   ch;
@@ -864,3 +1148,106 @@ static int ngx_read_http_proxy_status_li
         return NGX_AGAIN;
     }
 }
+
+
+#if 0
+
+static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+                                     char *conf)
+{
+    ngx_http_proxy_conf_t  *lcf = (ngx_http_proxy_conf_t *) conf;
+    char                   *url;
+    ngx_str_t              *value;
+    ngx_http_proxy_pass_t  *pass;
+
+    value = (ngx_str_t *) cf->args->elts;
+    url = value[1].data;
+
+    ngx_test_null(pass, ngx_push_array(lcf->proxy_pass), NGX_CONF_ERROR);
+
+    if (ngx_strncasecmp(url, "http://", 7) == 0) {
+        "invalid prefix in URL %s", url;
+    }
+
+    err = ngx_http_proxy_parse_upstream(url, u);
+
+    if (err) {
+        "%s %s", err, url;
+    }
+
+    h = ngx_gethostbyname(cmd->pool, u->host);
+
+    return NULL;
+}
+
+#endif
+
+
+static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
+                                           ngx_http_proxy_upstream_url_t *u)
+{
+    size_t  i;
+
+    if (url->data[0] == ':' || url->data[0] == '/') {
+        return "invalid upstream URL";
+    }
+
+    u->host.data = url->data;
+    u->host_header.data = url->data;
+
+    for (i = 1; i < url->len; i++) {
+        if (url->data[i] == ':') {
+            u->port_name.data = &url->data[i];
+            u->host.len = i;
+        }
+
+        if (url->data[i] == '/') {
+            u->uri.data = &url->data[i];
+            u->uri.len = url->len - i;
+            u->host_header.len = i;
+
+            if (u->host.len == 0) {
+                u->host.len = i;
+            }
+
+            if (u->port_name.data == NULL) {
+                return NULL;
+            }
+
+            u->port_name.len = &url->data[i] - u->port_name.data;
+
+            if (u->port_name.len > 0) {
+                u->port = ngx_atoi(u->port_name.data, u->port_name.len);
+                if (u->port > 0) {
+                    return NULL;
+                }
+            }
+
+            return "invalid port in upstream URL";
+        }
+    }
+
+    if (u->host.len == 0) {
+        u->host.len = i;
+    }
+
+    u->host_header.len = i;
+
+    u->uri.data = "/";
+    u->uri.len = 1;
+
+    if (u->port_name.data == NULL) {
+        return NULL;
+    }
+
+    u->port_name.len = &url->data[i] - u->port_name.data;
+
+    if (u->port_name.len > 0) {
+        u->port = ngx_atoi(u->port_name.data, u->port_name.len);
+        if (u->port > 0) {
+            return NULL;
+        }
+    }
+
+    return "invalid port in upstream URL";
+}
--- a/src/http/modules/ngx_http_event_proxy_handler.h
+++ b/src/http/modules/ngx_http_event_proxy_handler.h
@@ -20,6 +20,41 @@ typedef struct {
 } ngx_http_proxy_loc_conf_t;
 
 
+typedef struct {
+    ngx_str_t  host;
+    ngx_str_t  uri;
+    ngx_str_t  host_header;
+    ngx_str_t  port_name;
+    int        port;
+} ngx_http_proxy_upstream_url_t;
+
+
+typedef struct {
+    struct     sockaddr_in;
+    ngx_str_t  name;
+    time_t     access;
+    int        fails;
+} ngx_http_proxy_upstream_t;
+
+
+typedef struct {
+    int                         amount;
+    ngx_http_proxy_upstream_t  *upstreams;
+} ngx_http_proxy_upstream_farm_t;
+
+
+#if 0
+/* location /one/ { proxy_pass  http://localhost:9000/two/; } */
+
+typedef struct {
+                           /* "/one/" */
+                           /* "http://localhost:9000/two/" */
+                           /* "/two/" */
+                *upstream_farm;
+} ngx_http_proxy_pass_t;
+#endif
+
+
 typedef struct ngx_http_proxy_ctx_s  ngx_http_proxy_ctx_t;
 
 struct ngx_http_proxy_ctx_s {
@@ -30,9 +65,16 @@ struct ngx_http_proxy_ctx_s {
 
     int           hunk_n;
 
-    ngx_connection_t  *connection;
+    ngx_connection_t             *connection;
+    ngx_http_request_t           *request;
     ngx_http_proxy_headers_in_t  *headers_in;
 
+    ngx_http_proxy_upstream_farm_t   *upstream;
+    int                               cur_upstream;
+    int                               upstreams;
+
+    ngx_log_t    *log;
+
     ngx_hunk_t  *header_in;
     int          state;
     int          status;
@@ -43,6 +85,14 @@ struct ngx_http_proxy_ctx_s {
 };
 
 
+typedef struct {
+    char  *action;
+    char  *upstream;
+    char  *client;
+    char  *url;
+} ngx_http_proxy_log_ctx_t;
+
+
 extern ngx_module_t  ngx_http_proxy_module;
 
 
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -35,20 +35,13 @@ static ngx_command_t ngx_http_index_comm
 
 
 ngx_http_module_t  ngx_http_index_module_ctx = {
-    NGX_HTTP_MODULE,
-
     NULL,                                  /* create server config */
     NULL,                                  /* init server config */
+
     ngx_http_index_create_conf,            /* create location config */
     ngx_http_index_merge_conf,             /* merge location config */
 
-    NULL,                                  /* translate handler */
-
-    NULL,                                  /* output header filter */
-    NULL,                                  /* next output header filter */
-    NULL,                                  /* output body filter */
-    NULL,                                  /* next output body filter */
-
+    NULL                                   /* init filters */
 };
 
 
@@ -288,18 +281,18 @@ static char *ngx_http_index_merge_conf(n
 static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
                                       char *conf)
 {
-    ngx_http_index_conf_t *icf = (ngx_http_index_conf_t *) conf;
+    ngx_http_index_conf_t *lcf = (ngx_http_index_conf_t *) conf;
     int  i;
     ngx_str_t  *index, *value;
 
     value = (ngx_str_t *) cf->args->elts;
     for (i = 1; i < cf->args->nelts; i++) {
-        ngx_test_null(index, ngx_push_array(icf->indices), NGX_CONF_ERROR);
+        ngx_test_null(index, ngx_push_array(lcf->indices), NGX_CONF_ERROR);
         index->len = value[i].len;
         index->data = value[i].data;
 
-        if (icf->max_index_len < index->len) {
-            icf->max_index_len = index->len;
+        if (lcf->max_index_len < index->len) {
+            lcf->max_index_len = index->len;
         }
     }
 
--- a/src/http/modules/ngx_http_log_handler.c
+++ b/src/http/modules/ngx_http_log_handler.c
@@ -5,6 +5,7 @@
 #include <ngx_alloc.h>
 #include <ngx_time.h>
 #include <ngx_http.h>
+#include <ngx_http_config.h>
 
 
 ngx_http_module_t  ngx_http_log_module;
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -5,23 +5,11 @@
 #include <ngx_file.h>
 #include <ngx_hunk.h>
 #include <ngx_http.h>
+#include <ngx_http_config.h>
 #include <ngx_http_output_filter.h>
 
-ngx_http_module_t  ngx_http_static_module;
-
 
-#if 0
-/* STUB */
-static ngx_http_static_ctx_t module_ctx;
-
-void ngx_http_static_init()
-{
-     module_ctx.out = NULL;
-
-     ngx_http_static_module.ctx = &module_ctx;
-}
-/* */
-#endif
+ngx_http_module_t  ngx_http_static_module;
 
 
 int ngx_http_static_handler(ngx_http_request_t *r)
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -28,6 +28,7 @@ int  ngx_http_large_client_header = 1;
 int  ngx_http_url_in_error_log = 1;
 
 
+ngx_array_t  ngx_http_translate_handlers;
 ngx_array_t  ngx_http_index_handlers;
 
 
@@ -61,13 +62,12 @@ ngx_module_t  ngx_http_module = {
 
 static void ngx_http_init_filters(ngx_pool_t *pool, ngx_module_t **modules)
 {
-    int  i;
-    ngx_http_module_t  *module;
-    int (*ohf)(ngx_http_request_t *r);
-    int (*obf)(ngx_http_request_t *r, ngx_chain_t *ch);
+    int                      i;
+    ngx_http_module_t       *module;
+    ngx_http_conf_filter_t   cf;
 
-    ohf = NULL;
-    obf = NULL;
+    cf.output_header_filter = NULL;
+    cf.output_body_filter = NULL;
 
     for (i = 0; modules[i]; i++) {
         if (modules[i]->type != NGX_HTTP_MODULE_TYPE) {
@@ -76,18 +76,12 @@ static void ngx_http_init_filters(ngx_po
 
         module = (ngx_http_module_t *) modules[i]->ctx;
 
-        if (module->output_header_filter) {
-            module->next_output_header_filter = ohf;
-            ohf = module->output_header_filter;
-        }
-
-        if (module->output_body_filter) {
-            module->next_output_body_filter = obf;
-            obf = module->output_body_filter;
+        if (module->init_filters) {
+            module->init_filters(pool, &cf);
         }
     }
 
-    ngx_http_top_header_filter = ohf;
+    ngx_http_top_header_filter = cf.output_header_filter;
 }
 
 
@@ -119,10 +113,6 @@ static char *ngx_http_block(ngx_conf_t *
             continue;
         }
 
-        /* STUB */
-        module = (ngx_http_module_t *) ngx_modules[i]->ctx;
-        module->index = ngx_http_max_module;
-
         ngx_modules[i]->index = ngx_http_max_module++;
     }
 
@@ -139,7 +129,7 @@ static char *ngx_http_block(ngx_conf_t *
         module = (ngx_http_module_t *) ngx_modules[i]->ctx;
 
         if (module->create_loc_conf) {
-            ngx_test_null(ctx->loc_conf[module->index],
+            ngx_test_null(ctx->loc_conf[ngx_modules[i]->index],
                           module->create_loc_conf(cf->pool),
                           NGX_CONF_ERROR);
         }
@@ -173,6 +163,9 @@ static char *ngx_http_block(ngx_conf_t *
     /**/
 #endif
 
+    ngx_init_array(ngx_http_translate_handlers,
+                   cf->pool, 10, sizeof(ngx_http_handler_pt), NGX_CONF_ERROR);
+
     ngx_init_array(ngx_http_index_handlers,
                    cf->pool, 3, sizeof(ngx_http_handler_pt), NGX_CONF_ERROR);
 
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -38,14 +38,18 @@
 
 
 #define NGX_HTTP_OK                     200
+
 #define NGX_HTTP_SPECIAL_RESPONSE       300
 #define NGX_HTTP_MOVED_PERMANENTLY      301
 #define NGX_HTTP_MOVED_TEMPORARILY      302
 #define NGX_HTTP_NOT_MODIFIED           304
+
 #define NGX_HTTP_BAD_REQUEST            400
 #define NGX_HTTP_FORBIDDEN              403
 #define NGX_HTTP_NOT_FOUND              404
+#define NGX_HTTP_REQUEST_TIME_OUT       408
 #define NGX_HTTP_REQUEST_URI_TOO_LARGE  414
+
 #define NGX_HTTP_INTERNAL_SERVER_ERROR  500
 #define NGX_HTTP_NOT_IMPLEMENTED        501
 #define NGX_HTTP_BAD_GATEWAY            502
@@ -59,9 +63,8 @@
 
 
 typedef struct {
-    size_t  len;
-    char   *data;
-    int     offset;
+    ngx_str_t  name;
+    int        offset;
 } ngx_http_header_t;
 
 
@@ -71,8 +74,9 @@ typedef struct {
     ngx_table_elt_t  *host;
     ngx_table_elt_t  *connection;
     ngx_table_elt_t  *if_modified_since;
+    ngx_table_elt_t  *accept_encoding;
+
     ngx_table_elt_t  *user_agent;
-    ngx_table_elt_t  *accept_encoding;
 
     ngx_table_t      *headers;
 } ngx_http_headers_in_t;
@@ -101,34 +105,34 @@ typedef struct {
 typedef struct ngx_http_request_s ngx_http_request_t;
 
 struct ngx_http_request_s {
-    ngx_file_t  file;
+    ngx_connection_t    *connection;
 
-    void  **ctx;
-    void  **srv_conf;
-    void  **loc_conf;
+    void               **ctx;
+    void               **srv_conf;
+    void               **loc_conf;
 
-    ngx_pool_t  *pool;
-    ngx_hunk_t  *header_in;
+    ngx_file_t           file;
+
+    ngx_pool_t          *pool;
+    ngx_hunk_t          *header_in;
 
     ngx_http_headers_in_t   headers_in;
     ngx_http_headers_out_t  headers_out;
 
     int  (*handler)(ngx_http_request_t *r);
 
-    int    method;
-
     time_t  lingering_time;
 
-    int    http_version;
-    int    http_major;
-    int    http_minor;
+    int                  method;
+    int                  http_version;
+    int                  http_major;
+    int                  http_minor;
 
-    ngx_str_t  request_line;
-    ngx_str_t  uri;
-    ngx_str_t  exten;
-    ngx_http_request_t *main;
-
-    ngx_connection_t  *connection;
+    ngx_str_t            request_line;
+    ngx_str_t            uri;
+    ngx_str_t            args;
+    ngx_str_t            exten;
+    ngx_http_request_t  *main;
 
     u_int       in_addr;
 
@@ -192,32 +196,6 @@ typedef int (*ngx_http_output_body_filte
                                    (ngx_http_request_t *r, ngx_chain_t *chain);
 
 
-
-typedef struct {
-    int      index;
-
-    void  *(*create_srv_conf)(ngx_pool_t *p);
-    char  *(*init_srv_conf)(ngx_pool_t *p, void *conf);
-    void  *(*create_loc_conf)(ngx_pool_t *p);
-    char  *(*merge_loc_conf)(ngx_pool_t *p, void *prev, void *conf);
-
-    int    (*translate_handler)(ngx_http_request_t *r);
-
-    int    (*output_header_filter) (ngx_http_request_t *r);
-    int    (*next_output_header_filter) (ngx_http_request_t *r);
-
-    int    (*output_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
-    int    (*next_output_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
-} ngx_http_module_t;
-
-
-#define NGX_HTTP_MODULE        0x80000000
-
-#define NGX_HTTP_MODULE_TYPE   0x50545448   /* "HTTP" */
-
-
-#define ngx_http_get_module_srv_conf(r, module)  r->srv_conf[module.index]
-#define ngx_http_get_module_loc_conf(r, module)  r->loc_conf[module.index]
 #define ngx_http_get_module_ctx(r, module)       r->ctx[module.index]
 
 #define ngx_http_create_ctx(r, cx, module, size, error)                       \
@@ -243,7 +221,7 @@ int ngx_http_handler(ngx_http_request_t 
 
 
 int ngx_http_send_header(ngx_http_request_t *r);
-int ngx_http_special_response(ngx_http_request_t *r, int error);
+int ngx_http_special_response_handler(ngx_http_request_t *r, int error);
 
 
 time_t ngx_http_parse_time(char *value, size_t len);
@@ -269,12 +247,10 @@ extern int  ngx_http_discarded_buffer_si
 
 extern int  ngx_http_url_in_error_log;
 
+extern ngx_array_t  ngx_http_translate_handlers;
 extern ngx_array_t  ngx_http_index_handlers;
 
 
-extern ngx_http_module_t  *ngx_http_modules[];
-
-
 /* STUB */
 int ngx_http_log_handler(ngx_http_request_t *r);
 /**/
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -12,14 +12,39 @@ typedef struct {
 } ngx_http_conf_ctx_t;
 
 
+typedef struct {
+    int    (*output_header_filter) (ngx_http_request_t *r);
+    int    (*output_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+} ngx_http_conf_filter_t;
+
+
+typedef struct {
+    void  *(*create_srv_conf)(ngx_pool_t *p);
+    char  *(*init_srv_conf)(ngx_pool_t *p, void *conf);
+
+    void  *(*create_loc_conf)(ngx_pool_t *p);
+    char  *(*merge_loc_conf)(ngx_pool_t *p, void *prev, void *conf);
+
+    void   (*init_filters) (ngx_pool_t *p, ngx_http_conf_filter_t *cf);
+} ngx_http_module_t;
+
+
+#define NGX_HTTP_MODULE_TYPE      0x50545448   /* "HTTP" */
+
+
 #define NGX_HTTP_MAIN_CONF        0x1000000
 #define NGX_HTTP_SRV_CONF         0x2000000
 #define NGX_HTTP_LOC_CONF         0x6000000
 
+
 #define NGX_HTTP_SRV_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, srv_conf)
 #define NGX_HTTP_LOC_CONF_OFFSET  offsetof(ngx_http_conf_ctx_t, loc_conf)
 
 
+#define ngx_http_get_module_srv_conf(r, module)  r->srv_conf[module.index]
+#define ngx_http_get_module_loc_conf(r, module)  r->loc_conf[module.index]
+
+
 int ngx_http_config_modules(ngx_pool_t *pool, ngx_module_t **modules);
 
 
@@ -28,8 +53,5 @@ extern ngx_module_t  ngx_http_module;
 
 extern int (*ngx_http_top_header_filter) (ngx_http_request_t *r);
 
-extern void **ngx_srv_conf;
-extern void **ngx_loc_conf;
-
 
 #endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -19,12 +19,15 @@ int ngx_http_proxy_handler(ngx_http_requ
 
 static int ngx_http_core_index_handler(ngx_http_request_t *r);
 
+static int ngx_http_core_init(ngx_pool_t *pool);
+
+static void *ngx_http_core_create_srv_conf(ngx_pool_t *pool);
+static char *ngx_http_core_init_srv_conf(ngx_pool_t *pool, void *conf);
+static void *ngx_http_core_create_loc_conf(ngx_pool_t *pool);
+
 static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy);
 static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd,
                                                                   char *dummy);
-static void *ngx_http_core_create_srv_conf(ngx_pool_t *pool);
-static char *ngx_http_core_init_srv_conf(ngx_pool_t *pool, void *conf);
-static void *ngx_http_core_create_loc_conf(ngx_pool_t *pool);
 static char *ngx_set_listen(ngx_conf_t *cf, ngx_command_t *cmd, char *conf);
 
 
@@ -108,24 +111,18 @@ static ngx_command_t  ngx_http_core_comm
      NGX_HTTP_LOC_CONF_OFFSET,
      offsetof(ngx_http_core_loc_conf_t, lingering_timeout)},
 
-    {ngx_string(""), 0, NULL, 0, 0}
+    {ngx_null_string, 0, NULL, 0, 0}
 };
 
 
 ngx_http_module_t  ngx_http_core_module_ctx = {
-    NGX_HTTP_MODULE,
-
     ngx_http_core_create_srv_conf,         /* create server config */
     ngx_http_core_init_srv_conf,           /* init server config */
+
     ngx_http_core_create_loc_conf,         /* create location config */
     NULL,                                  /* merge location config */
 
-    ngx_http_core_translate_handler,       /* translate handler */
-
-    NULL,                                  /* output header filter */
-    NULL,                                  /* next output header filter */
-    NULL,                                  /* output body filter */
-    NULL                                   /* next output body filter */
+    NULL                                   /* init filters */
 };
 
 
@@ -134,13 +131,14 @@ ngx_module_t  ngx_http_core_module = {
     &ngx_http_core_module_ctx,             /* module context */
     ngx_http_core_commands,                /* module directives */
     NGX_HTTP_MODULE_TYPE,                  /* module type */
-    NULL                                   /* init module */
+    ngx_http_core_init                     /* init module */
 };
 
 
 int ngx_http_handler(ngx_http_request_t *r)
 {
     int                      rc, a, n, i;
+    ngx_http_handler_pt     *h;
     ngx_http_module_t       *module;
     ngx_http_conf_ctx_t     *ctx;
     ngx_http_in_port_t      *in_port;
@@ -149,8 +147,8 @@ int ngx_http_handler(ngx_http_request_t 
 
     r->connection->unexpected_eof = 0;
 
+    r->keepalive = 1;
     r->lingering_close = 1;
-    r->keepalive = 0;
 
 #if 1
     r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
@@ -213,34 +211,25 @@ ngx_log_debug(r->connection->log, "srv_c
 ngx_log_debug(r->connection->log, "loc_conf: %0x" _ r->loc_conf);
 
     /* run translation phase */
-    for (i = 0; ngx_modules[i]; i++) {
-        if (ngx_modules[i]->type != NGX_HTTP_MODULE_TYPE) {
+
+    h = (ngx_http_handler_pt *) ngx_http_translate_handlers.elts;
+    for (i = 0; i < ngx_http_translate_handlers.nelts; i++) {
+        rc = h[i](r);
+
+        if (rc == NGX_DECLINED) {
             continue;
         }
 
-        module = (ngx_http_module_t *) ngx_modules[i]->ctx;
-
-        if (module->translate_handler == NULL) {
-            continue;
-        }
-
-        rc = module->translate_handler(r);
         if (rc == NGX_OK) {
             break;
         }
 
         if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-            return ngx_http_special_response(r, rc);
+            return rc;
         }
     }
 
-    rc = r->handler(r);
-
-    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-        return ngx_http_special_response(r, rc);
-    }
-
-    return rc;
+    return r->handler(r);
 }
 
 
@@ -252,27 +241,27 @@ int ngx_http_core_translate_handler(ngx_
     ngx_table_elt_t            *h;
     ngx_http_server_name_t     *s_name;
     ngx_http_core_srv_conf_t   *scf;
-    ngx_http_core_loc_conf_t  **lcf, *loc_conf;
+    ngx_http_core_loc_conf_t   *lcf, **plcf;
 
     scf = (ngx_http_core_srv_conf_t *)
-                     ngx_http_get_module_srv_conf(r, ngx_http_core_module_ctx);
+                         ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
     /* find location config */
-    lcf = (ngx_http_core_loc_conf_t **) scf->locations.elts;
+    plcf = (ngx_http_core_loc_conf_t **) scf->locations.elts;
     for (i = 0; i < scf->locations.nelts; i++) {
-ngx_log_debug(r->connection->log, "trans: %s" _ lcf[i]->name.data);
-         if (r->uri.len < lcf[i]->name.len) {
+ngx_log_debug(r->connection->log, "trans: %s" _ plcf[i]->name.data);
+         if (r->uri.len < plcf[i]->name.len) {
              continue;
          }
 
-         rc = ngx_strncmp(r->uri.data, lcf[i]->name.data, lcf[i]->name.len);
+         rc = ngx_strncmp(r->uri.data, plcf[i]->name.data, plcf[i]->name.len);
 
          if (rc < 0) {
              break;
          }
 
          if (rc == 0) {
-             r->loc_conf = lcf[i]->loc_conf;
+             r->loc_conf = plcf[i]->loc_conf;
          }
     }
 
@@ -286,10 +275,10 @@ ngx_log_debug(r->connection->log, "trans
         return NGX_OK;
     }
 
-    loc_conf = (ngx_http_core_loc_conf_t *)
-                     ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
+    lcf = (ngx_http_core_loc_conf_t *)
+                         ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-ngx_log_debug(r->connection->log, "doc_root: %08x" _ &loc_conf->doc_root);
+ngx_log_debug(r->connection->log, "doc_root: %08x" _ &lcf->doc_root);
 
     s_name = (ngx_http_server_name_t *) scf->server_names.elts;
 
@@ -314,14 +303,14 @@ ngx_log_debug(r->connection->log, "doc_r
     port_len = (r->port != 80) ? r->port_name.len : 0;
 
     /* "+ 7" is "http://" */
-    if (loc_conf->doc_root.len > 7 + s_name[0].name.len + port_len) {
-        len = loc_conf->doc_root.len;
+    if (lcf->doc_root.len > 7 + s_name[0].name.len + port_len) {
+        len = lcf->doc_root.len;
         f_offset = 0;
         l_offset = len - (7 + s_name[0].name.len + port_len);
 
     } else {
         len = 7 + s_name[0].name.len + port_len;
-        f_offset = len - loc_conf->doc_root.len;
+        f_offset = len - lcf->doc_root.len;
         l_offset = 0;
     }
 
@@ -334,8 +323,8 @@ ngx_log_debug(r->connection->log, "doc_r
     r->file.name.data = buf + f_offset;
     location = buf + l_offset;
 
-    last = ngx_cpystrn(ngx_cpystrn(r->file.name.data, loc_conf->doc_root.data,
-                                   loc_conf->doc_root.len + 1),
+    last = ngx_cpystrn(ngx_cpystrn(r->file.name.data, lcf->doc_root.data,
+                                   lcf->doc_root.len + 1),
                        r->uri.data, r->uri.len + 1);
 
     r->file.name.len = last - r->file.name.data;
@@ -344,9 +333,9 @@ ngx_log_debug(r->connection->log, "HTTP 
 
 #if (WIN9X)
 
-    /* There is no way to open file or directory in Win9X with
-       one syscall: Win9X has not FILE_FLAG_BACKUP_SEMANTICS flag.
-       so we need to check its type before opening */
+    /* There is no way to open a file or a directory in Win9X with
+       one syscall: Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag.
+       so we need to check its type before the opening */
 
     r->file.info.dwFileAttributes = GetFileAttributes(r->file.name.data);
     if (r->file.info.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
@@ -451,7 +440,7 @@ ngx_log_debug(r->connection->log, "HTTP 
         return NGX_HTTP_MOVED_PERMANENTLY;
     }
 
-    /* TODO: r->handler = loc_conf->default_handler; */
+    /* TODO: r->handler = lcf->default_handler; */
     /* STUB */ r->handler = ngx_http_static_handler;
 
     return NGX_OK;
@@ -503,7 +492,7 @@ int ngx_http_redirect(ngx_http_request_t
 
     /* log request */
 
-    return ngx_http_close_request(r);
+    return ngx_http_close_request(r, 0);
 }
 
 
@@ -514,17 +503,20 @@ int ngx_http_error(ngx_http_request_t *r
 
     /* log request */
 
-    ngx_http_special_response(r, error);
-    return ngx_http_close_request(r);
+    ngx_http_special_response_handler(r, error);
+    return ngx_http_close_request(r, 0);
 }
 
 
-int ngx_http_close_request(ngx_http_request_t *r)
+int ngx_http_close_request(ngx_http_request_t *r, int error)
 {
     ngx_connection_t    *c;
     ngx_http_log_ctx_t  *ctx;
 
     c = r->connection;
+    if (error) {
+        r->headers_out.status = error;
+    }
 
     ngx_http_log_handler(r);
 
@@ -573,14 +565,26 @@ int ngx_http_internal_redirect(ngx_http_
 }
 
 
+static int ngx_http_core_init(ngx_pool_t *pool)
+{
+    ngx_http_handler_pt  *h;
+
+    ngx_test_null(h, ngx_push_array(&ngx_http_translate_handlers), NGX_ERROR);
+
+    *h = ngx_http_core_translate_handler;
+
+    return NGX_OK;
+}
+
+
 static char *ngx_server_block(ngx_conf_t *cf, ngx_command_t *cmd, char *dummy)
 {
-    int                        i, j;
-    char                      *rv;
-    ngx_http_module_t         *module;
-    ngx_http_conf_ctx_t       *ctx, *prev;
-    ngx_http_core_srv_conf_t  *scf;
-    ngx_http_core_loc_conf_t **lcf;
+    int                         i, j;
+    char                       *rv;
+    ngx_http_module_t          *module;
+    ngx_http_conf_ctx_t        *ctx, *prev;
+    ngx_http_core_srv_conf_t   *scf;
+    ngx_http_core_loc_conf_t  **plcf;
 
     ngx_test_null(ctx,
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
@@ -604,13 +608,13 @@ static char *ngx_server_block(ngx_conf_t
         module = (ngx_http_module_t *) ngx_modules[i]->ctx;
 
         if (module->create_srv_conf) {
-            ngx_test_null(ctx->srv_conf[module->index],
+            ngx_test_null(ctx->srv_conf[ngx_modules[i]->index],
                           module->create_srv_conf(cf->pool),
                           NGX_CONF_ERROR);
         }
 
         if (module->create_loc_conf) {
-            ngx_test_null(ctx->loc_conf[module->index],
+            ngx_test_null(ctx->loc_conf[ngx_modules[i]->index],
                           module->create_loc_conf(cf->pool),
                           NGX_CONF_ERROR);
         }
@@ -625,10 +629,10 @@ static char *ngx_server_block(ngx_conf_t
         return rv;
 
 
-    scf = ctx->srv_conf[ngx_http_core_module_ctx.index];
+    scf = ctx->srv_conf[ngx_http_core_module.index];
     scf->ctx = ctx;
 
-    lcf = (ngx_http_core_loc_conf_t **)scf->locations.elts;
+    plcf = (ngx_http_core_loc_conf_t **)scf->locations.elts;
 
     for (i = 0; ngx_modules[i]; i++) {
         if (ngx_modules[i]->type != NGX_HTTP_MODULE_TYPE) {
@@ -639,7 +643,7 @@ static char *ngx_server_block(ngx_conf_t
 
         if (module->init_srv_conf) {
             if (module->init_srv_conf(cf->pool,
-                                      ctx->srv_conf[module->index])
+                                      ctx->srv_conf[ngx_modules[i]->index])
                                                            == NGX_CONF_ERROR) {
                 return NGX_CONF_ERROR;
             }
@@ -647,16 +651,16 @@ static char *ngx_server_block(ngx_conf_t
 
         if (module->merge_loc_conf) {
             if (module->merge_loc_conf(cf->pool,
-                                       prev->loc_conf[module->index],
-                                       ctx->loc_conf[module->index])
+                                       prev->loc_conf[ngx_modules[i]->index],
+                                       ctx->loc_conf[ngx_modules[i]->index])
                                                            == NGX_CONF_ERROR) {
                 return NGX_CONF_ERROR;
             }
 
             for (j = 0; j < scf->locations.nelts; j++) {
                 if (module->merge_loc_conf(cf->pool,
-                                           ctx->loc_conf[module->index],
-                                           lcf[j]->loc_conf[module->index])
+                                      ctx->loc_conf[ngx_modules[i]->index],
+                                      plcf[j]->loc_conf[ngx_modules[i]->index])
                                                            == NGX_CONF_ERROR) {
                     return NGX_CONF_ERROR;
                 }
@@ -676,7 +680,7 @@ static char *ngx_location_block(ngx_conf
     ngx_http_module_t         *module;
     ngx_http_conf_ctx_t       *ctx, *prev;
     ngx_http_core_srv_conf_t  *scf;
-    ngx_http_core_loc_conf_t  *lcf, **loc;
+    ngx_http_core_loc_conf_t  *lcf, **plcf;
 
     ngx_test_null(ctx,
                   ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
@@ -697,7 +701,7 @@ static char *ngx_location_block(ngx_conf
         module = (ngx_http_module_t *) ngx_modules[i]->ctx;
 
         if (module->create_loc_conf) {
-            ngx_test_null(ctx->loc_conf[module->index],
+            ngx_test_null(ctx->loc_conf[ngx_modules[i]->index],
                           module->create_loc_conf(cf->pool),
                           NGX_CONF_ERROR);
         }
@@ -712,8 +716,8 @@ static char *ngx_location_block(ngx_conf
 
     scf = (ngx_http_core_srv_conf_t *)
                                      ctx->srv_conf[ngx_http_core_module.index];
-    ngx_test_null(loc, ngx_push_array(&scf->locations), NGX_CONF_ERROR);
-    *loc = lcf;
+    ngx_test_null(plcf, ngx_push_array(&scf->locations), NGX_CONF_ERROR);
+    *plcf = lcf;
 
     cf->ctx = ctx;
     rv = ngx_conf_parse(cf, NULL);
@@ -789,7 +793,7 @@ static void *ngx_http_core_create_loc_co
     lcf->doc_root.len = 4;
     lcf->doc_root.data = "html";
 
-    lcf->send_timeout = 10;
+    lcf->send_timeout = 10000;
     lcf->discarded_buffer_size = 1500;
     lcf->lingering_time = 30000;
     lcf->lingering_timeout = 5000;
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -57,12 +57,13 @@ typedef struct {
     void      **loc_conf;      /* pointer to modules loc_conf,
                                   used in translation handler */
 
-    ngx_str_t   doc_root;      /* 'root' */
+    ngx_str_t   doc_root;                /* root */
 
-    time_t      send_timeout;  /* 'send_timeout' */
-    size_t      discarded_buffer_size;   /* 'discarded_buffer_size */
-    time_t      lingering_time;          /* 'lingering_time */
-    ngx_msec_t  lingering_timeout;       /* 'lingering_timeout */
+    time_t      send_timeout;            /* send_timeout */
+    size_t      send_lowat;              /* send_lowa */
+    size_t      discarded_buffer_size;   /* discarded_buffer_size */
+    time_t      lingering_time;          /* lingering_time */
+    ngx_msec_t  lingering_timeout;       /* lingering_timeout */
 } ngx_http_core_loc_conf_t;
 
 
@@ -87,7 +88,9 @@ int ngx_http_core_translate_handler(ngx_
 
 int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri);
 int ngx_http_error(ngx_http_request_t *r, int error);
-int ngx_http_close_request(ngx_http_request_t *r);
+
+int ngx_http_finalize_request(ngx_http_request_t *r, int error);
+int ngx_http_close_request(ngx_http_request_t *r, int error);
 
 
 #endif /* _NGX_HTTP_CORE_H_INCLUDED_ */
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -19,13 +19,11 @@
 
 
 static int ngx_http_init_request(ngx_event_t *ev);
-static int ngx_http_process_request_header(ngx_event_t *ev);
-
+static int ngx_http_process_request(ngx_event_t *ev);
 static int ngx_http_process_request_line(ngx_http_request_t *r);
 static int ngx_http_process_request_headers(ngx_http_request_t *r);
 static int ngx_http_process_request_header_line(ngx_http_request_t *r);
-
-static int ngx_http_event_request_handler(ngx_http_request_t *r);
+static int ngx_http_request_handler(ngx_http_request_t *r, int error);
 
 static int ngx_http_writer(ngx_event_t *ev);
 static int ngx_http_block_read(ngx_event_t *ev);
@@ -36,8 +34,7 @@ static int ngx_http_set_lingering_close(
 static int ngx_http_lingering_close_handler(ngx_event_t *ev);
 
 static int ngx_http_close_connection(ngx_event_t *ev);
-static int ngx_http_header_parse_error(ngx_http_request_t *r,
-                                       int parse_err, int err);
+static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err);
 static size_t ngx_http_log_error(void *data, char *buf, size_t len);
 
 
@@ -56,26 +53,26 @@ static char *header_errors[] = {
 
 
 static ngx_http_header_t headers_in[] = {
-    { 4, "Host", offsetof(ngx_http_headers_in_t, host) },
-    { 10, "Connection", offsetof(ngx_http_headers_in_t, connection) },
-    { 17, "If-Modified-Since",
-                           offsetof(ngx_http_headers_in_t,if_modified_since) },
+    { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host) },
+    { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection) },
+    { ngx_string("If-Modified-Since"), 
+                          offsetof(ngx_http_headers_in_t,if_modified_since) },
 
-    { 10, "User-Agent", offsetof(ngx_http_headers_in_t, user_agent) },
+    { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent) },
 
-    { 0, NULL, 0 }
+    { ngx_null_string, 0 }
 };
 
 
 int ngx_http_init_connection(ngx_connection_t *c)
 {
-    ngx_event_t         *ev;
+    ngx_event_t         *rev;
     ngx_http_log_ctx_t  *ctx;
 
-    ev = c->read;
-    ev->event_handler = ngx_http_init_request;
+    rev = c->read;
+    rev->event_handler = ngx_http_init_request;
 
-    ev->close_handler = ngx_http_close_connection;
+    rev->close_handler = ngx_http_close_connection;
     c->write->close_handler = ngx_http_close_connection;
 
     ngx_test_null(c->addr_text.data, ngx_palloc(c->pool, c->addr_text_max_len),
@@ -97,52 +94,48 @@ int ngx_http_init_connection(ngx_connect
 
 #if (HAVE_DEFERRED_ACCEPT)
 
-    if (ev->ready) {
-        return ngx_http_init_request(ev);
+    if (rev->ready) {
+        return ngx_http_init_request(rev);
     }
 
 #endif
 
-    ngx_add_timer(ev, c->post_accept_timeout);
-    ev->timer_set = 1;
+    ngx_add_timer(rev, c->post_accept_timeout);
+    rev->timer_set = 1;
 
 #if (USE_KQUEUE)
 
-    return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
+    return ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
 
 #else
 
-#if (HAVE_CLEAR_EVENT) /* kqueue */
+    /* kqueue */
 
     if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
-        return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
+        return ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
     }
 
-#endif
-
-#if (HAVE_EDGE_EVENT) /* epoll */ || (HAVE_AIO_EVENT) /* aio, iocp */
+    /* aio, iocp, epoll */
 
-    if (ngx_event_flags & (NGX_HAVE_EDGE_EVENT|NGX_HAVE_AIO_EVENT)) {
-        return ngx_http_init_request(ev);
+    if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
+        return ngx_http_init_request(rev);
     }
 
-#endif
-
     /* select, poll, /dev/poll */
 
-    return ngx_add_event(ev, NGX_READ_EVENT, NGX_LEVEL_EVENT);
+    return ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT);
 
 #endif /* USE_KQUEUE */
 }
 
 
-static int ngx_http_init_request(ngx_event_t *ev)
+static int ngx_http_init_request(ngx_event_t *rev)
 {
     ngx_connection_t     *c;
     ngx_http_request_t   *r;
     ngx_http_conf_ctx_t  *ctx;
 
-    c = (ngx_connection_t *) ev->data;
+    c = (ngx_connection_t *) rev->data;
     c->sent = 0;
 
     ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)),
@@ -165,12 +158,12 @@ static int ngx_http_init_request(ngx_eve
     r->pipeline = c->pipeline;
     r->header_in = c->buffer;
 
-    ngx_test_null(r->pool, ngx_create_pool(ngx_http_request_pool_size, ev->log),
+    ngx_test_null(r->pool, ngx_create_pool(ngx_http_request_pool_size, c->log),
                   NGX_ERROR);
 
     ngx_test_null(r->ctx,
                   ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module),
-                  ngx_http_close_request(r));
+                  ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR));
 
     ctx = (ngx_http_conf_ctx_t *) c->ctx;
     r->srv_conf = ctx->srv_conf;
@@ -180,36 +173,34 @@ static int ngx_http_init_request(ngx_eve
     r->headers_out.content_length = -1;
     r->headers_out.last_modified_time = -1;
 
-    ev->event_handler = ngx_http_process_request_header;
+    rev->event_handler = ngx_http_process_request;
     r->state_handler = ngx_http_process_request_line;
 
-    return ngx_http_process_request_header(ev);
+    return ngx_http_process_request(rev);
 }
 
 
-static int ngx_http_process_request_header(ngx_event_t *ev)
+static int ngx_http_process_request(ngx_event_t *rev)
 {
-    int                  n, rc, again;
+    int                  n, rc;
     ngx_connection_t    *c;
     ngx_http_request_t  *r;
-    ngx_http_log_ctx_t  *ctx;
+    ngx_http_log_ctx_t  *lcx;
 
-    c = (ngx_connection_t *) ev->data;
+    c = (ngx_connection_t *) rev->data;
     r = (ngx_http_request_t *) c->data;
 
-    ngx_log_debug(ev->log, "http process request");
+    ngx_log_debug(c->log, "http process request");
+
+    if (rev->timedout) {
+        return ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
+    }
 
     do {
 
         if (r->header_read) {
-            if (r->header_in->end - r->header_in->last == 0) {
-                again = 1;
-            } else {
-                again = 0;
-            }
-
             r->header_read = 0;
-            ngx_log_debug(ev->log, "http preread %d" _
+            ngx_log_debug(c->log, "http preread %d" _
                           r->header_in->last - r->header_in->pos);
 
         } else {
@@ -219,38 +210,32 @@ static int ngx_http_process_request_head
             if (n == NGX_AGAIN) {
                 if (!r->header_timeout_set) {
 
-                    if (ev->timer_set) {
-                        ngx_del_timer(ev);
+                    if (rev->timer_set) {
+                        ngx_del_timer(rev);
                     } else {
-                        ev->timer_set = 1;
+                        rev->timer_set = 1;
                     }
 
-                    ngx_add_timer(ev, ngx_http_client_header_timeout);
+                    ngx_add_timer(rev, ngx_http_client_header_timeout);
                     r->header_timeout_set = 1;
                 }
+
                 return NGX_AGAIN;
             }
 
             if (n == NGX_ERROR) {
-                return ngx_http_close_request(r);
+                return ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
             }
 
-            ngx_log_debug(ev->log, "http read %d" _ n);
+            ngx_log_debug(c->log, "http read %d" _ n);
 
             if (n == 0) {
                 ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client has prematurely closed connection");
-                return ngx_http_close_request(r);
+                              "client closed prematurely connection");
+                return ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
             }
 
             r->header_in->last += n;
-
-            if (ngx_http_large_client_header
-                                  && r->header_in->end == r->header_in->last) {
-                again = 1;
-            } else {
-                again = 0;
-            }
         }
 
         /* the state_handlers are called in the following order:
@@ -258,51 +243,56 @@ static int ngx_http_process_request_head
             ngx_http_process_request_headers(r) */
 
         do {
-            /* state_handlers return NGX_OK when the whole header done */
             rc = (r->state_handler)(r);
 
-            if (rc == NGX_ERROR) {
-                return rc;
-            }
-
         } while (rc == NGX_AGAIN && r->header_in->pos < r->header_in->last);
 
-#if (HAVE_AIO_EVENT) /* aio, iocp */
+    } while (rc == NGX_AGAIN
+             && (rev->ready || ngx_event_flags & NGX_HAVE_AIO_EVENT));
+
+    if (rc >= NGX_OK) {
 
-        if (ngx_event_flags & NGX_HAVE_AIO_EVENT) {
-            again = 1;
+        /* HTTP header done */
+
+        rev->event_handler = ngx_http_block_read;
+
+        if (rc != NGX_OK) {
+            return ngx_http_finalize_request(r, rc);
         }
 
-#endif
-
-    } while (rc == NGX_AGAIN && again);
+        lcx = r->connection->log->data;
+        lcx->action = "processing client request";
 
-    if (rc == NGX_OK) {
-        /* HTTP header done */
+        rc = ngx_http_handler(r);
 
-        if (ev->timer_set) {
-            ngx_del_timer(ev);
-            ev->timer_set = 0;
+        /* a handler is still busy */
+        if (rc == NGX_BUSY) {
+            return rc;
         }
 
-        return ngx_http_event_request_handler(r);
-
-    } else { /* NGX_AGAIN */
-
-        if (!r->header_timeout_set) {
-
-            if (ev->timer_set) {
-                ngx_del_timer(ev);
-            } else {
-                ev->timer_set = 1;
-            }
-
-            ngx_add_timer(ev, ngx_http_client_header_timeout);
-            r->header_timeout_set = 1;
+        if (rc == NGX_ERROR) {
+            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        return rc;
+        return ngx_http_finalize_request(r, rc);
+
     }
+
+    /* NGX_AGAIN */
+
+    if (!r->header_timeout_set) {
+
+        if (rev->timer_set) {
+            ngx_del_timer(rev);
+        } else {
+            rev->timer_set = 1;
+        }
+
+        ngx_add_timer(rev, ngx_http_client_header_timeout);
+        r->header_timeout_set = 1;
+    }
+
+    return rc;
 }
 
 
@@ -310,29 +300,40 @@ static int ngx_http_process_request_line
 {
     int                  rc, offset;
     ngx_connection_t    *c;
-    ngx_http_log_ctx_t  *ctx;
+    ngx_http_log_ctx_t  *lcx;
 
     rc = ngx_read_http_request_line(r);
 
     c = r->connection;
 
     /* a request line has been parsed successfully */
+
     if (rc == NGX_OK) {
+
         /* copy URI */
-        r->uri.len = (r->args_start ? r->args_start - 1 : r->uri_end)
-                                                                - r->uri_start;
+
+        if (r->args_start) {
+            r->uri.len = r->args_start - 1 - r->uri_start;
+        } else {
+            r->uri.len = r->uri_end - r->uri_start;
+        }
+
         ngx_test_null(r->uri.data, ngx_palloc(r->pool, r->uri.len + 1),
-                      ngx_http_close_request(r));
+                      NGX_HTTP_INTERNAL_SERVER_ERROR);
+
         ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
 
+        r->request_line.len = r->request_end - r->request_start;
+
         /* if the large client headers are enabled then
            we need to copy a request line */
 
-        r->request_line.len = r->request_end - r->request_start;
         if (ngx_http_large_client_header) {
+
             ngx_test_null(r->request_line.data,
                           ngx_palloc(r->pool, r->request_line.len + 1),
-                          ngx_http_close_request(r));
+                          NGX_HTTP_INTERNAL_SERVER_ERROR);
+
             ngx_cpystrn(r->request_line.data, r->request_start,
                         r->request_line.len + 1);
 
@@ -342,33 +343,59 @@ static int ngx_http_process_request_line
         }
 
         /* copy URI extention if it exists */
+
         if (r->uri_ext) {
-            r->exten.len = (r->args_start ? r->args_start - 1 : r->uri_end)
-                                                                  - r->uri_ext;
+            if (r->args_start) {
+                r->exten.len = r->args_start - 1 - r->uri_ext;
+            } else {
+                r->exten.len = r->uri_end - r->uri_ext;
+            }
+
             ngx_test_null(r->exten.data,
                           ngx_palloc(r->pool, r->exten.len + 1), 
-                          ngx_http_close_request(r));
+                          NGX_HTTP_INTERNAL_SERVER_ERROR);
+
             ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
         }
 
+        /* copy URI arguments if they exist */
+
+        if (r->args_start && r->uri_end > r->args_start) {
+            r->args.len = r->uri_end - r->args_start;
+
+            ngx_test_null(r->args.data,
+                          ngx_palloc(r->pool, r->args.len + 1),
+                          NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+            ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1);
+        }
+
 #if 1
         if (r->exten.data == NULL) {
             r->exten.data = "";
         }
-        ngx_log_debug(r->connection->log, "HTTP: %d, %d, '%s', '%s'" _
+        if (r->args.data == NULL) {
+            r->args.data = "";
+        }
+        ngx_log_debug(r->connection->log, "HTTP: %d, %d, '%s', '%s', '%s'" _
                       r->method _ r->http_version _
-                      r->uri.data _ r->exten.data);
+                      r->uri.data _ r->exten.data _ r->args.data);
         if (r->exten.data[0] == '\0') {
             r->exten.data = NULL;
         }
+        if (r->args.data[0] == '\0') {
+            r->args.data = NULL;
+        }
 #endif
 
-        ctx = r->connection->log->data;
+        lcx = r->connection->log->data;
+
         if (ngx_http_url_in_error_log) {
-            ngx_test_null(ctx->url,
+            ngx_test_null(lcx->url,
                           ngx_palloc(r->pool, r->uri_end - r->uri_start + 1),
-                          ngx_http_close_request(r));
-            ngx_cpystrn(ctx->url, r->uri_start, r->uri_end - r->uri_start + 1);
+                          NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+            ngx_cpystrn(lcx->url, r->uri_start, r->uri_end - r->uri_start + 1);
         }
 
         /* if we need to parse the headers then return NGX_AGAIN
@@ -382,13 +409,21 @@ static int ngx_http_process_request_line
         r->headers_in.headers = ngx_create_table(r->pool, 10);
 
         r->state_handler = ngx_http_process_request_headers;
-        ctx->action = "reading client request headers";
+        lcx->action = "reading client request headers";
+
+        if (ngx_http_large_client_header
+            && r->header_in->pos == r->header_in->last)
+        {
+            r->header_in->pos = r->header_in->last = r->header_in->start;
+        }
 
         return NGX_AGAIN;
 
     /* there was error while a request line parsing */
+
     } else if (rc != NGX_AGAIN) {
-        return ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
+        ngx_http_header_parse_error(r, rc);
+        return NGX_HTTP_BAD_REQUEST;
     }
 
     /* NGX_AGAIN: a request line parsing is still not complete */
@@ -405,9 +440,8 @@ static int ngx_http_process_request_line
             offset = r->request_start - r->header_in->start;
 
             if (offset == 0) {
-                return ngx_http_header_parse_error(r,
-                                               NGX_HTTP_PARSE_TOO_LONG_URI,
-                                               NGX_HTTP_REQUEST_URI_TOO_LARGE);
+                ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
+                return NGX_HTTP_REQUEST_URI_TOO_LARGE;
             }
 
             ngx_memcpy(r->header_in->start, r->request_start,
@@ -427,9 +461,8 @@ static int ngx_http_process_request_line
             }
 
         } else {
-            return ngx_http_header_parse_error(r,
-                                               NGX_HTTP_PARSE_TOO_LONG_URI,
-                                               NGX_HTTP_REQUEST_URI_TOO_LARGE);
+            ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_URI);
+            return NGX_HTTP_REQUEST_URI_TOO_LARGE;
         }
     }
 
@@ -447,14 +480,22 @@ static int ngx_http_process_request_head
         rc = ngx_read_http_header_line(r, r->header_in);
 
         /* a header line has been parsed successfully */
+
         if (rc == NGX_OK) {
             if (ngx_http_process_request_header_line(r) == NGX_ERROR) {
-                return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            if (ngx_http_large_client_header
+                && r->header_in->pos == r->header_in->last)
+            {
+                r->header_in->pos = r->header_in->last = r->header_in->start;
             }
 
             return NGX_AGAIN;
 
         /* a whole header has been parsed successfully */
+
         } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
             ngx_log_debug(r->connection->log, "HTTP header done");
 
@@ -468,9 +509,9 @@ static int ngx_http_process_request_head
 
             } else {
                 if (r->http_version > NGX_HTTP_VERSION_10) {
-                    return ngx_http_header_parse_error(r,
-                                                 NGX_HTTP_PARSE_NO_HOST_HEADER,
-                                                 NGX_HTTP_BAD_REQUEST);
+                    ngx_http_header_parse_error(r,
+                                                NGX_HTTP_PARSE_NO_HOST_HEADER);
+                    return NGX_HTTP_BAD_REQUEST;
                 }
                 r->headers_in.host_name_len = 0;
             }
@@ -479,8 +520,10 @@ static int ngx_http_process_request_head
             return NGX_OK;
 
         /* there was error while a header line parsing */
+
         } else if (rc != NGX_AGAIN) {
-            return ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
+            ngx_http_header_parse_error(r, rc);
+            return NGX_HTTP_BAD_REQUEST;
         }
 
         /* NGX_AGAIN: a header line parsing is still not complete */
@@ -494,9 +537,9 @@ static int ngx_http_process_request_head
                 offset = r->header_name_start - r->header_in->start;
 
                 if (offset == 0) {
-                    return ngx_http_header_parse_error(r,
-                                                NGX_HTTP_PARSE_TOO_LONG_HEADER,
-                                                NGX_HTTP_BAD_REQUEST);
+                    ngx_http_header_parse_error(r,
+                                                NGX_HTTP_PARSE_TOO_LONG_HEADER);
+                    return NGX_HTTP_BAD_REQUEST;
                 }
 
                 ngx_memcpy(r->header_in->start, r->header_name_start,
@@ -510,9 +553,8 @@ static int ngx_http_process_request_head
                 r->header_end -= offset;
 
             } else {
-                return ngx_http_header_parse_error(r,
-                                               NGX_HTTP_PARSE_TOO_LONG_HEADER,
-                                               NGX_HTTP_BAD_REQUEST);
+                ngx_http_header_parse_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER);
+                return NGX_HTTP_BAD_REQUEST;
             }
 
         }
@@ -524,17 +566,17 @@ static int ngx_http_process_request_head
 
 static int ngx_http_process_request_header_line(ngx_http_request_t *r)
 {
-    int  i;
-    ngx_table_elt_t *h;
+    int               i;
+    ngx_table_elt_t  *h;
 
     ngx_test_null(h, ngx_push_table(r->headers_in.headers), NGX_ERROR);
 
-    /* if large client headers are enabled then
-       we need to copy header name and value */
-
     h->key.len = r->header_name_end - r->header_name_start;
     h->value.len = r->header_end - r->header_start;
 
+    /* if the large client headers are enabled then
+       we need to copy the header name and value */
+
     if (ngx_http_large_client_header) {
         ngx_test_null(h->key.data, ngx_palloc(r->pool, h->key.len + 1),
                       NGX_ERROR);
@@ -550,12 +592,12 @@ static int ngx_http_process_request_head
         h->value.data[h->value.len] = '\0';
     }
 
-    for (i = 0; headers_in[i].len != 0; i++) {
-        if (headers_in[i].len != h->key.len) {
+    for (i = 0; headers_in[i].name.len != 0; i++) {
+        if (headers_in[i].name.len != h->key.len) {
             continue;
         }
 
-        if (ngx_strcasecmp(headers_in[i].data, h->key.data) == 0) {
+        if (ngx_strcasecmp(headers_in[i].name.data, h->key.data) == 0) {
             *((ngx_table_elt_t **)
                         ((char *) &r->headers_in + headers_in[i].offset)) = h;
         }
@@ -568,166 +610,130 @@ static int ngx_http_process_request_head
 }
 
 
-static int ngx_http_event_request_handler(ngx_http_request_t *r)
+int ngx_http_finalize_request(ngx_http_request_t *r, int error)
 {
-    int                  rc, event;
-    ngx_msec_t           timeout;
-    ngx_event_t         *rev, *wev;
-    ngx_http_log_ctx_t  *ctx;
+    int                        rc, event;
+    ngx_msec_t                 timeout;
+    ngx_event_t               *rev, *wev;
+    ngx_http_core_loc_conf_t  *lcf;
+
+    rc = error;
 
-    rev = r->connection->read;
-    wev = r->connection->write;
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+
+        rev = r->connection->read;
 
-    if (rev->timer_set) {
-        ngx_del_timer(rev);
-        rev->timer_set = 0;
+        if (rev->timer_set) {
+            ngx_del_timer(rev);
+        } else {
+            rev->timer_set = 1;
+        }
+
+        rc = ngx_http_special_response_handler(r, rc);
     }
 
-    rev->event_handler = ngx_http_block_read;
-
-    ctx = r->connection->log->data;
-    ctx->action = "processing client request";
+    /* a handler has done its work completely */
 
-    rc = ngx_http_handler(r);
-
-    /* handler is still busy */
-    if (rc == NGX_WAITING)
-        return rc;
+    if (rc == NGX_OK) {
 
-    /* handler has done its work but transfer is still not completed */
-    if (rc == NGX_AGAIN) {
+        if (r->keepalive != 0) {
+            return ngx_http_set_keepalive(r);
+        }
 
-        /* STUB: timeouts should be reworked */
-        if (r->connection->sent > 0) {
-            ngx_log_debug(r->connection->log, "sent: " OFF_FMT _
-                          r->connection->sent);
-            timeout = (ngx_msec_t) (r->connection->sent * 10);
-            ngx_log_debug(r->connection->log, "timeout: %d" _ timeout);
-            ngx_add_timer(wev, timeout);
-
-        } else {
-            ngx_add_timer(wev, 10000);
+        if (r->lingering_close) {
+            return ngx_http_set_lingering_close(r);
         }
 
-        wev->event_handler = ngx_http_writer;
+        return ngx_http_close_request(r, 0);
+    }
+
+    /* NGX_AGAIN: a handler has done its work
+                  but the transfer is still not completed */
+
+    lcf = (ngx_http_core_loc_conf_t *)
+                            ngx_http_get_module_loc_conf(r->main ? r->main : r,
+                                                         ngx_http_core_module);
+    wev = r->connection->write;
+    wev->event_handler = ngx_http_writer;
+    wev->timer_set = 1;
+    ngx_add_timer(wev, lcf->send_timeout);
 
 #if (USE_KQUEUE)
 
 #if (HAVE_LOWAT_EVENT) /* kqueue's NOTE_LOWAT */
-        wev->lowat = /* STUB */ NGX_LOWAT;
+    wev->lowat = lcf->send_lowat;
 #endif
 
-        if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) {
-            return ngx_http_close_request(r);
-        }
+    if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) {
+        return ngx_http_close_request(r, 0);
+    }
 
-        return rc;
+    return rc;
 
 #else
 
-#if (HAVE_AIO_EVENT) || (HAVE_EDGE_EVENT) /* aio, iocp, epoll */
+    /* aio, iocp, epoll */
 
-        if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
-            return rc;
-        }
-
-#endif
+    if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
+        return rc;
+    }
 
 #if (HAVE_LOWAT_EVENT) /* kqueue's NOTE_LOWAT */
 
-        if (ngx_event_flags & NGX_HAVE_LOWAT_EVENT) {
-            wev->lowat = /* STUB */ NGX_LOWAT;
-        }
-
-#endif
-
-#if (HAVE_CLEAR_EVENT) /* kqueue */
-
-        if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
-            event = NGX_CLEAR_EVENT;
-
-        } else {
-            event = NGX_LEVEL_EVENT;
-        }
-
-#else /* select, poll, /dev/poll */
-
-        event = NGX_LEVEL_EVENT;
+    if (ngx_event_flags & NGX_HAVE_LOWAT_EVENT) {
+        wev->lowat = lcf->send_lowat;
+    }
 
 #endif
 
-        if (ngx_add_event(wev, NGX_WRITE_EVENT, event) == NGX_ERROR) {
-            return ngx_http_close_request(r);
-        }
+    /* kqueue */
 
-        return rc;
-
+    if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
+        event = NGX_CLEAR_EVENT;
 
-#endif /* USE_KQUEUE */
-
-    }
+    /* select, poll, /dev/poll */
 
-    if (rc == NGX_ERROR) {
-        /* log http request */
-        return ngx_http_close_request(r);
+    } else {
+        event = NGX_LEVEL_EVENT;
     }
 
-    if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
-        return ngx_http_special_response(r, rc);
-
-    /* rc == NGX_OK */
-
-    if (r->keepalive == 0) {
-        if (r->lingering_close) {
-            return ngx_http_set_lingering_close(r);
-
-        } else {
-            return ngx_http_close_request(r);
-        }
+    if (ngx_add_event(wev, NGX_WRITE_EVENT, event) == NGX_ERROR) {
+        return ngx_http_close_request(r, 0);
     }
 
-    /* keepalive */
+    return rc;
 
-    return ngx_http_set_keepalive(r);
+#endif /* USE_KQUEUE */
 }
 
 
-static int ngx_http_writer(ngx_event_t *ev)
+static int ngx_http_writer(ngx_event_t *wev)
 {
-    int rc;
+    int                        rc;
     ngx_msec_t                 timeout;
     ngx_connection_t          *c;
     ngx_http_request_t        *r;
-    ngx_http_core_loc_conf_t  *conf;
+    ngx_http_core_loc_conf_t  *lcf;
 
-    c = (ngx_connection_t *) ev->data;
+    c = (ngx_connection_t *) wev->data;
     r = (ngx_http_request_t *) c->data;
 
     rc = ngx_http_output_filter(r, NULL);
 
-    ngx_log_debug(ev->log, "output filter in writer: %d" _ rc);
+    ngx_log_debug(c->log, "output filter in writer: %d" _ rc);
 
     if (rc == NGX_AGAIN) {
 
-        /* STUB: timeouts should be reworked */
-        if (c->sent > 0) {
-            conf = (ngx_http_core_loc_conf_t *)
-                        ngx_http_get_module_loc_conf(r->main ? r->main : r,
-                                                     ngx_http_core_module_ctx);
-
-            timeout = (ngx_msec_t) (c->sent * conf->send_timeout);
+        lcf = (ngx_http_core_loc_conf_t *)
+                            ngx_http_get_module_loc_conf(r->main ? r->main : r,
+                                                         ngx_http_core_module);
+        if (wev->timer_set) {
+            ngx_del_timer(wev);
+        } else {
+            wev->timer_set = 1;
+        }
 
-            ngx_log_debug(ev->log, "sent: " OFF_FMT _ c->sent);
-            ngx_log_debug(ev->log, "timeout: %d" _ timeout);
-
-            if (ev->timer_set) {
-                ngx_del_timer(ev);
-            } else {
-                ev->timer_set = 1;
-            }
-
-            ngx_add_timer(ev, timeout);
-        }
+        ngx_add_timer(wev, lcf->send_timeout);
 
         return rc;
     }
@@ -737,20 +743,17 @@ static int ngx_http_writer(ngx_event_t *
 
     /* rc == NGX_OK */
 
-    ngx_log_debug(ev->log, "http writer done");
+    ngx_log_debug(c->log, "http writer done");
 
-    if (r->keepalive == 0) {
-        if (r->lingering_close) {
-            return ngx_http_set_lingering_close(r);
-
-        } else {
-            return ngx_http_close_request(r);
-        }
+    if (r->keepalive != 0) {
+        return ngx_http_set_keepalive(r);
     }
 
-    /* keepalive */
+    if (r->lingering_close) {
+        return ngx_http_set_lingering_close(r);
+    }
 
-    return ngx_http_set_keepalive(r);
+    return ngx_http_close_request(r, 0);
 }
 
 
@@ -813,30 +816,35 @@ static int ngx_http_read_discarded_body(
 
     ngx_log_debug(ev->log, "http read discarded body");
 
-    if (ev->timedout)
+    if (ev->timedout) {
         return NGX_ERROR;
+    }
 
     c = (ngx_connection_t *) ev->data;
     r = (ngx_http_request_t *) c->data;
 
     lcf = (ngx_http_core_loc_conf_t *)
-                     ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
+                         ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (r->discarded_buffer == NULL)
+    if (r->discarded_buffer == NULL) {
         ngx_test_null(r->discarded_buffer,
                       ngx_palloc(r->pool, lcf->discarded_buffer_size),
                       NGX_ERROR);
+    }
 
     size = r->client_content_length;
-    if (size > lcf->discarded_buffer_size)
+    if (size > lcf->discarded_buffer_size) {
         size = lcf->discarded_buffer_size;
+    }
 
     n = ngx_event_recv(c, r->discarded_buffer, size);
-    if (n == NGX_ERROR)
+    if (n == NGX_ERROR) {
         return NGX_ERROR;
+    }
 
-    if (n == NGX_AGAIN)
+    if (n == NGX_AGAIN) {
         return NGX_OK;
+    }
 
     r->client_content_length -= n;
     /* XXX: what if r->client_content_length == 0 ? */
@@ -854,11 +862,10 @@ static int ngx_http_set_keepalive(ngx_ht
 
     c = (ngx_connection_t *) r->connection;
     rev = c->read;
-    wev = c->write;
 
     ctx = (ngx_http_log_ctx_t *) c->log->data;
     ctx->action = "closing request";
-    ngx_http_close_request(r);
+    ngx_http_close_request(r, 0);
 
     if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
         if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
@@ -876,8 +883,8 @@ static int ngx_http_set_keepalive(ngx_ht
     /* pipelined request */
     if (h->pos < h->last) {
 
-        /* We do not know here whether pipelined request is complete
-           so if large client headers are not enabled
+        /* We do not know here whether a pipelined request is complete
+           so if the large client headers are not enabled
            we need to copy the data to the start of c->buffer.
            This copy should be rare because clients that support
            pipelined requests (Mozilla 1.x, Opera 6.x) are still rare */
@@ -898,6 +905,7 @@ static int ngx_http_set_keepalive(ngx_ht
 
     h->pos = h->last = h->start;
     rev->event_handler = ngx_http_keepalive_handler;
+    wev = c->write;
 
     if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
         if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
@@ -925,62 +933,60 @@ static int ngx_http_set_keepalive(ngx_ht
 }
 
 
-static int ngx_http_keepalive_handler(ngx_event_t *ev)
+static int ngx_http_keepalive_handler(ngx_event_t *rev)
 {
     ssize_t n;
     ngx_connection_t    *c;
-    ngx_http_log_ctx_t  *ctx;
+    ngx_http_log_ctx_t  *lctx;
 
-    c = (ngx_connection_t *) ev->data;
+    c = (ngx_connection_t *) rev->data;
 
-    ngx_log_debug(ev->log, "http keepalive handler");
+    ngx_log_debug(c->log, "http keepalive handler");
 
-    if (ev->timedout) {
+    if (rev->timedout) {
         return NGX_DONE;
     }
 
-    /* MSIE closes keepalive connection with RST flag
+    /* MSIE closes a keepalive connection with RST flag
        so we ignore ECONNRESET here */
 
-    ev->ignore_econnreset = 1;
+    rev->ignore_econnreset = 1;
     ngx_set_socket_errno(0);
     n = ngx_event_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
-    ev->ignore_econnreset = 0;
+    rev->ignore_econnreset = 0;
 
     if (n == NGX_AGAIN || n == NGX_ERROR) {
         return n;
     }
 
-    ctx = (ngx_http_log_ctx_t *) ev->log->data;
-    ev->log->handler = NULL;
+    lctx = (ngx_http_log_ctx_t *) rev->log->data;
+    rev->log->handler = NULL;
 
     if (n == 0) {
-        ngx_log_error(NGX_LOG_INFO, ev->log, ngx_socket_errno,
-                      "client %s closed keepalive connection", ctx->client);
+        ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno,
+                      "client %s closed keepalive connection", lctx->client);
         return NGX_DONE;
     }
 
     c->buffer->last += n;
-    ev->log->handler = ngx_http_log_error;
-    ctx->action = "reading client request line";
+    rev->log->handler = ngx_http_log_error;
+    lctx->action = "reading client request line";
 
-    return ngx_http_init_request(ev);
+    return ngx_http_init_request(rev);
 }
 
 
 static int ngx_http_set_lingering_close(ngx_http_request_t *r)
 {
-    int                        blocked;
-    ngx_event_t               *rev, *wev;
+    ngx_event_t               *rev;
     ngx_connection_t          *c;
     ngx_http_core_loc_conf_t  *lcf;
 
     c = r->connection;
     rev = c->read;
-    wev = c->write;
 
     lcf = (ngx_http_core_loc_conf_t *)
-                     ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
+                         ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     r->lingering_time = ngx_time() + lcf->lingering_time / 1000;
     r->connection->read->event_handler = ngx_http_lingering_close_handler;
@@ -995,36 +1001,36 @@ static int ngx_http_set_lingering_close(
 
     if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
         if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
-            return ngx_http_close_request(r);
+            return ngx_http_close_request(r, 0);
         }
-        blocked = 1;
         rev->blocked = 0;
-
-    } else {
-        blocked = 0;
     }
 
-    if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
-        if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
-            return ngx_http_close_request(r);
+#if !(USE_KQUEUE)
+
+    if (c->write->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
+        if (ngx_del_event(c->write, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
+            return ngx_http_close_request(r, 0);
         }
     }
 
+#endif
+
     if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
         ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
                       ngx_shutdown_socket_n " failed");
-        return ngx_http_close_request(r);
+        return ngx_http_close_request(r, 0);
     }
 
-#if (HAVE_AIO_EVENT) /* aio, iocp */
+#if (USE_KQUEUE)
 
-    if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) || blocked) {
+    if (rev->ready) {
         return ngx_http_lingering_close_handler(rev);
     }
 
 #else
 
-    if (blocked) {
+    if (rev->ready || (ngx_event_flags & NGX_HAVE_AIO_EVENT)) {
         return ngx_http_lingering_close_handler(rev);
     }
 
@@ -1034,30 +1040,30 @@ static int ngx_http_set_lingering_close(
 }
 
 
-static int ngx_http_lingering_close_handler(ngx_event_t *ev)
+static int ngx_http_lingering_close_handler(ngx_event_t *rev)
 {
-    ssize_t              n;
-    ngx_msec_t           timer;
-    ngx_connection_t    *c;
-    ngx_http_request_t  *r;
+    ssize_t                    n;
+    ngx_msec_t                 timer;
+    ngx_connection_t          *c;
+    ngx_http_request_t        *r;
     ngx_http_core_loc_conf_t  *lcf;
 
-    ngx_log_debug(ev->log, "http lingering close handler");
-
-    c = (ngx_connection_t *) ev->data;
+    c = (ngx_connection_t *) rev->data;
     r = (ngx_http_request_t *) c->data;
 
-    if (ev->timedout) {
-        return ngx_http_close_request(r);
+    ngx_log_debug(c->log, "http lingering close handler");
+
+    if (rev->timedout) {
+        return ngx_http_close_request(r, 0);
     }
 
     timer = r->lingering_time - ngx_time();
     if (timer <= 0) {
-        return ngx_http_close_request(r);
+        return ngx_http_close_request(r, 0);
     }
 
     lcf = (ngx_http_core_loc_conf_t *)
-                     ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
+                         ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (r->discarded_buffer == NULL) {
 
@@ -1072,29 +1078,32 @@ static int ngx_http_lingering_close_hand
         } else {
             ngx_test_null(r->discarded_buffer,
                           ngx_palloc(c->pool, lcf->discarded_buffer_size),
-                          ngx_http_close_request(r));
+                          ngx_http_close_request(r, 0));
         }
     }
 
-    n = ngx_event_recv(c, r->discarded_buffer, lcf->discarded_buffer_size);
+    do {
+        n = ngx_event_recv(c, r->discarded_buffer, lcf->discarded_buffer_size);
 
-    ngx_log_debug(ev->log, "lingering read: %d" _ n);
+        ngx_log_debug(c->log, "lingering read: %d" _ n);
 
-    if (n == NGX_ERROR || n == 0) {
-        return ngx_http_close_request(r);
-    }
+        if (n == NGX_ERROR || n == 0) {
+            return ngx_http_close_request(r, 0);
+        }
+
+    } while (rev->ready);
 
     timer *= 1000;
     if (timer > lcf->lingering_timeout) {
         timer = lcf->lingering_timeout;
     }
 
-    if (ev->timer_set) {
-        ngx_del_timer(ev);
+    if (rev->timer_set) {
+        ngx_del_timer(rev);
     } else {
-        ev->timer_set = 1;
+        rev->timer_set = 1;
     }
-    ngx_add_timer(ev, timer);
+    ngx_add_timer(rev, timer);
 
     return NGX_OK;
 }
@@ -1106,8 +1115,7 @@ static int ngx_http_close_connection(ngx
 }
 
 
-static int ngx_http_header_parse_error(ngx_http_request_t *r,
-                                       int parse_err, int err)
+static void ngx_http_header_parse_error(ngx_http_request_t *r, int parse_err)
 {
     ngx_http_log_ctx_t  *ctx;
 
@@ -1126,8 +1134,6 @@ static int ngx_http_header_parse_error(n
     }
 
     r->connection->log->handler = ngx_http_log_error;
-
-    return ngx_http_error(r, err);
 }
 
 
@@ -1135,10 +1141,11 @@ static size_t ngx_http_log_error(void *d
 {
     ngx_http_log_ctx_t *ctx = (ngx_http_log_ctx_t *) data;
 
-    if (ctx->url)
+    if (ctx->url) {
         return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
                             ctx->action, ctx->client, ctx->url);
-    else
+    } else {
         return ngx_snprintf(buf, len, " while %s, client: %s",
                             ctx->action, ctx->client);
+    }
 }
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -10,26 +10,23 @@
 #include <ngx_conf_file.h>
 
 #include <ngx_http.h>
+#include <ngx_http_config.h>
 #include <ngx_http_write_filter.h>
 
 
+static void ngx_http_header_filter_init(ngx_pool_t *pool,
+                                        ngx_http_conf_filter_t *cf);
 static int ngx_http_header_filter(ngx_http_request_t *r);
 
 
 ngx_http_module_t  ngx_http_header_filter_module_ctx = {
-    NGX_HTTP_MODULE,
-
     NULL,                                  /* create server config */
     NULL,                                  /* init server config */
+
     NULL,                                  /* create location config */
     NULL,                                  /* merge location config */
 
-    NULL,                                  /* translate handler */
-
-    ngx_http_header_filter,                /* output header filter */
-    NULL,                                  /* next output header filter */
-    NULL,                                  /* output body filter */
-    NULL                                   /* next output body filter */
+    ngx_http_header_filter_init            /* init filters */
 };
 
 
@@ -295,3 +292,10 @@ static int ngx_http_header_filter(ngx_ht
 
     return ngx_http_write_filter(r, ch);
 }
+
+
+static void ngx_http_header_filter_init(ngx_pool_t *pool,
+                                        ngx_http_conf_filter_t *cf)
+{
+    cf->output_header_filter = ngx_http_header_filter;
+}
--- a/src/http/ngx_http_output_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -16,6 +16,8 @@ static int ngx_http_output_filter_copy_h
 static void *ngx_http_output_filter_create_conf(ngx_pool_t *pool);
 static char *ngx_http_output_filter_merge_conf(ngx_pool_t *pool,
                                                void *parent, void *child);
+static void ngx_http_output_filter_init(ngx_pool_t *pool,
+                                        ngx_http_conf_filter_t *cf);
 
 
 static ngx_command_t  ngx_http_output_filter_commands[] = {
@@ -31,20 +33,13 @@ static ngx_command_t  ngx_http_output_fi
 
 
 static ngx_http_module_t  ngx_http_output_filter_module_ctx = {
-    NGX_HTTP_MODULE,
-
     NULL,                                  /* create server config */
     NULL,                                  /* init server config */
+
     ngx_http_output_filter_create_conf,    /* create location config */
     ngx_http_output_filter_merge_conf,     /* merge location config */
 
-    NULL,                                  /* translate handler */
-
-    NULL,                                  /* output header filter */
-    NULL,                                  /* next output header filter */
-    (int (*)(ngx_http_request_t *, ngx_chain_t *))
-        ngx_http_output_filter,            /* output body filter */
-    NULL                                   /* next output body filter */
+    ngx_http_output_filter_init            /* output body filter */
 };
 
 
@@ -58,7 +53,12 @@ ngx_module_t  ngx_http_output_filter_mod
 
 
 
+static int (*next_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+
+
+#if 0
 #define next_filter  ngx_http_output_filter_module_ctx.next_output_body_filter
+#endif
 
 #define need_to_copy(r, hunk)                                             \
             (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)                \
@@ -300,6 +300,14 @@ static int ngx_http_output_filter_copy_h
 }
 
 
+static void ngx_http_output_filter_init(ngx_pool_t *pool,
+                                        ngx_http_conf_filter_t *cf)
+{
+    next_filter = cf->output_body_filter;
+    cf->output_body_filter = NULL;
+}
+
+
 static void *ngx_http_output_filter_create_conf(ngx_pool_t *pool)
 {
     ngx_http_output_filter_conf_t *conf;
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -39,6 +39,14 @@ static char error_404_page[] =
 ;
 
 
+static char error_408_page[] =
+"<html>" CRLF
+"<head><title>408 Request Time-out</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>408 Request Time-out</h1></center>" CRLF
+;
+
+
 static char error_414_page[] =
 "<html>" CRLF
 "<head><title>414 Request-URI Too Large</title></head>" CRLF
@@ -55,35 +63,54 @@ static char error_500_page[] =
 ;
 
 
+static char error_502_page[] =
+"<html>" CRLF
+"<head><title>502 Bad Gateway</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>502 Bad Gateway</h1></center>" CRLF
+;
+
+
+static char error_504_page[] =
+"<html>" CRLF
+"<head><title>504 Gateway Time-out</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>504 Gateway Time-out</h1></center>" CRLF
+;
+
+
 static ngx_str_t error_pages[] = {
-    { 0, NULL},  /* 301 */
-    { 0, NULL},  /* 302 */
-    { 0, NULL},  /* 303 */
-    { 0, NULL},  /* 304 */
+    ngx_null_string,             /* 301 */
+    ngx_null_string,             /* 302 */
+    ngx_null_string,             /* 303 */
 
-    { sizeof(error_400_page) - 1, error_400_page },
-    { 0, NULL},  /* 401 */
-    { 0, NULL},  /* 402 */
-    { sizeof(error_403_page) - 1, error_403_page },
-    { sizeof(error_404_page) - 1, error_404_page },
-    { 0, NULL},  /* 405 */
-    { 0, NULL},  /* 406 */
-    { 0, NULL},  /* 407 */
-    { 0, NULL},  /* 408 */
-    { 0, NULL},  /* 409 */
-    { 0, NULL},  /* 410 */
-    { 0, NULL},  /* 411 */
-    { 0, NULL},  /* 412 */
-    { 0, NULL},  /* 413 */
-    { sizeof(error_414_page) - 1, error_414_page },
-    { 0, NULL},  /* 415 */
-    { 0, NULL},  /* 416 */
+    ngx_string(error_400_page),
+    ngx_null_string,             /* 401 */
+    ngx_null_string,             /* 402 */
+    ngx_string(error_403_page),
+    ngx_string(error_404_page),
+    ngx_null_string,             /* 405 */
+    ngx_null_string,             /* 406 */
+    ngx_null_string,             /* 407 */
+    ngx_string(error_408_page),
+    ngx_null_string,             /* 409 */
+    ngx_null_string,             /* 410 */
+    ngx_null_string,             /* 411 */
+    ngx_null_string,             /* 412 */
+    ngx_null_string,             /* 413 */
+    ngx_string(error_414_page),
+    ngx_null_string,             /* 415 */
+    ngx_null_string,             /* 416 */
 
-    { sizeof(error_500_page) - 1, error_500_page }
+    ngx_string(error_500_page),
+    ngx_null_string,             /* 501 */
+    ngx_string(error_502_page),
+    ngx_null_string,             /* 503 */
+    ngx_string(error_504_page)
 };
 
 
-int ngx_http_special_response(ngx_http_request_t *r, int error)
+int ngx_http_special_response_handler(ngx_http_request_t *r, int error)
 {
     int          err, len;
     ngx_hunk_t  *message, *tail;
@@ -96,10 +123,10 @@ int ngx_http_special_response(ngx_http_r
         err = error - NGX_HTTP_MOVED_PERMANENTLY;
 
     } else if (error < NGX_HTTP_INTERNAL_SERVER_ERROR) {
-        err = error - NGX_HTTP_BAD_REQUEST + 4;
+        err = error - NGX_HTTP_BAD_REQUEST + 3;
 
     } else {
-        err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 4 + 17;
+        err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 3 + 17;
     }
 
     if (r->keepalive != 0) {
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -16,6 +16,8 @@
 static void *ngx_http_write_filter_create_conf(ngx_pool_t *pool);
 static char *ngx_http_write_filter_merge_conf(ngx_pool_t *pool,
                                               void *parent, void *child);
+static void ngx_http_write_filter_init(ngx_pool_t *pool,
+                                       ngx_http_conf_filter_t *cf);
 
 
 static ngx_command_t ngx_http_write_filter_commands[] = {
@@ -31,19 +33,13 @@ static ngx_command_t ngx_http_write_filt
 
 
 ngx_http_module_t  ngx_http_write_filter_module_ctx = {
-    NGX_HTTP_MODULE,
-
     NULL,                                  /* create server config */
     NULL,                                  /* init server config */
+
     ngx_http_write_filter_create_conf,     /* create location config */
     ngx_http_write_filter_merge_conf,      /* merge location config */
 
-    NULL,                                  /* translate handler */
-
-    NULL,                                  /* output header filter */
-    NULL,                                  /* next output header filter */
-    ngx_http_write_filter,                 /* output body filter */
-    NULL,                                  /* next output body filter */
+    ngx_http_write_filter_init             /* init filters */
 };
 
 
@@ -156,6 +152,13 @@ int ngx_http_write_filter(ngx_http_reque
 }
 
 
+static void ngx_http_write_filter_init(ngx_pool_t *pool,
+                                       ngx_http_conf_filter_t *cf)
+{
+    cf->output_body_filter = ngx_http_write_filter;
+}
+
+
 static void *ngx_http_write_filter_create_conf(ngx_pool_t *pool)
 {
     ngx_http_write_filter_conf_t *conf;