nginx-0.0.1-2002-09-02-18:48:24 import
diff --git a/src/http/modules/ngx_http_header_filter.c b/src/http/modules/ngx_http_header_filter.c
index efe0744..9cb1f4c 100644
--- a/src/http/modules/ngx_http_header_filter.c
+++ b/src/http/modules/ngx_http_header_filter.c
@@ -2,6 +2,7 @@
 #include <nginx.h>
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_string.h>
 #include <ngx_hunk.h>
 #include <ngx_http.h>
@@ -25,12 +26,8 @@
     ngx_hunk_t   *h;
     ngx_chain_t  *ch;
 
-    ngx_test_null(h, ngx_get_hunk(r->pool, 1024, 0, 64),
-                  /* STUB */
-                  -1);
-/*
-                  NGX_HTTP_FILTER_ERROR);
-*/
+    ngx_test_null(h, ngx_create_temp_hunk(r->pool, 1024, 0, 64),
+                  NGX_ERROR);
 
     status = r->headers_out->status - NGX_HTTP_OK;
 
diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c
index 20d0b9e..0900a42 100644
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -26,7 +26,7 @@
 {
     int rc;
     ngx_hunk_t  *h;
-    ngx_chain_t *ch;
+    ngx_http_log_ctx_t  *ctx;
 
 /*
     ngx_http_event_static_handler_loc_conf_t  *cf;
@@ -36,6 +36,10 @@
 
 */
 
+    ngx_http_discard_body(r);
+    ctx = r->connection->log->data;
+    ctx->action = "sending response";
+
     r->fd = ngx_open_file(r->filename, NGX_FILE_RDONLY);
     if (r->fd == -1) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
@@ -45,7 +49,7 @@
         return -1;
     }
 
-    if (ngx_stat_fd(r->fd, &r->file_info) == -1) {
+    if (ngx_stat_fd(r->fd, &r->fileinfo) == -1) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
                       "ngx_http_static_handler: "
                       ngx_stat_fd_n " %s failed", r->filename);
@@ -54,9 +58,9 @@
     }
 
     r->headers_out->status = NGX_HTTP_OK;
-    r->headers_out->content_length = ngx_file_size(r->file_info);
+    r->headers_out->content_length = ngx_file_size(r->fileinfo);
 /*
-    r->headers_out->last_modified = ngx_file_mtime(r->file_info);
+    r->headers_out->last_modified = ngx_file_mtime(r->fileinfo);
 */
 
     /* STUB */
@@ -73,39 +77,22 @@
     /* TODO: NGX_HTTP_INTERNAL_SERVER_ERROR is too late */
 
     /* STUB */
-    ngx_test_null(h, ngx_get_hunk(r->pool, 1024, 0, 64),
-                  /* STUB */
-                  -1);
-/*
-    ngx_test_null(h, ngx_create_hunk(r->pool), NGX_HTTP_INTERNAL_SERVER_ERROR);
-*/
-    h->type = NGX_HUNK_FILE|NGX_HUNK_LAST;
-    h->fd = r->fd;
-    h->pos.file = 0;
-    h->last.file = ngx_file_size(r->file_info);
-
-    /* STUB */
-    ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)),
-                  /* STUB */
-                  -1);
-/*
-                  NGX_HTTP_FILTER_ERROR);
-*/
-
-/*
-    ngx_test_null(ch, ngx_create_chain(r->pool),
+    ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
                   NGX_HTTP_INTERNAL_SERVER_ERROR);
-*/
-    ch->hunk = h;
-    ch->next = NULL;
+
+    h->type = NGX_HUNK_FILE|NGX_HUNK_LAST;
+    h->pos.file = 0;
+    h->last.file = ngx_file_size(r->fileinfo);
 
     /* STUB */
-    rc = ngx_http_write_filter(r, ch);
-    ngx_log_debug(r->connection->log, "write_filter: %d" _ rc);
+    ngx_test_null(h->file, ngx_pcalloc(r->pool, sizeof(ngx_file_t)),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+    h->file->fd = r->fd;
+    h->file->log = r->connection->log;
+
+    rc = ngx_http_output_filter(r, h);
+    ngx_log_debug(r->connection->log, "0 output_filter: %d" _ rc);
     return rc;
-/*
-    return ngx_http_filter(r, ch);
-*/
 }
 
 #if 0
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index 5410d31..7e8cad5 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_string.h>
+#include <ngx_socket.h>
 #include <ngx_listen.h>
 #include <ngx_http.h>
 
@@ -17,8 +18,11 @@
 {
     ngx_listen_t  *ls;
 
+    ngx_http_server.request_pool_size = 16384;
     ngx_http_server.header_timeout = 20000;
-    ngx_http_server.buff_size = 1024;
+    ngx_http_server.header_buffer_size = 1024;
+    ngx_http_server.discarded_buffer_size = 1500;
+
 #if (WIN32)
     ngx_http_server.doc_root = "html";
 #else
@@ -26,8 +30,11 @@
 #endif
     ngx_http_server.doc_root_len = strlen(ngx_http_server.doc_root) + 1;
 
+
+    ngx_http_output_filter_init();
     ngx_http_write_filter_init();
 
+
     ls = ngx_push_array(ngx_listening_sockets);
     ngx_memzero(ls, sizeof(ngx_listen_t));
 
@@ -57,6 +64,7 @@
     ls->server = &ngx_http_server;
     ls->log = log;
 
+
     return 1;
 }
 
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index fe89874..3b943d6 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -5,7 +5,7 @@
 #include <ngx_config.h>
 #include <ngx_types.h>
 #include <ngx_hunk.h>
-#include <ngx_file.h>
+#include <ngx_files.h>
 #include <ngx_connection.h>
 
 
@@ -25,6 +25,7 @@
 
 
 #define NGX_HTTP_OK                     200
+#define NGX_HTTP_SPECIAL_RESPONSE       300
 #define NGX_HTTP_MOVED_PERMANENTLY      302
 #define NGX_HTTP_BAD_REQUEST            400
 #define NGX_HTTP_NOT_FOUND              404
@@ -45,7 +46,11 @@
 typedef struct {
     char          *doc_root;
     size_t         doc_root_len;
-    size_t         buff_size;
+
+    size_t         request_pool_size;
+
+    size_t         header_buffer_size;
+    size_t         discarded_buffer_size;
 
     unsigned int   header_timeout;
 } ngx_http_server_t;
@@ -88,7 +93,7 @@
     int    filename_len;
     int  (*handler)(ngx_http_request_t *r);
 
-    ngx_file_info_t file_info;
+    ngx_file_info_t fileinfo;
 
     int    method;
 
@@ -104,7 +109,11 @@
 
     int       filter;
 
+    ssize_t   client_content_length;
+    char     *discarded_buffer;
+
     unsigned  header_timeout:1;
+    unsigned  process_header:1;
 
     unsigned  header_only:1;
     unsigned  unusual_uri:1;
@@ -134,6 +143,9 @@
 #define NGX_INDEX "index.html"
 
 
+/* STUB */
+int ngx_http_init(ngx_pool_t *pool, ngx_log_t *log);
+
 int ngx_http_init_connection(ngx_connection_t *c);
 
 
diff --git a/src/http/ngx_http_event.c b/src/http/ngx_http_event.c
index 63fc29a..7783462 100644
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -2,7 +2,7 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_string.h>
-#include <ngx_file.h>
+#include <ngx_files.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
 #include <ngx_hunk.h>
@@ -10,6 +10,12 @@
 
 #include <ngx_http.h>
 
+/* STUB */
+#include <ngx_http_output_filter.h>
+
+int ngx_http_static_handler(ngx_http_request_t *r);
+
+
 int ngx_http_init_connection(ngx_connection_t *c);
 
 static int ngx_http_init_request(ngx_event_t *ev);
@@ -17,8 +23,19 @@
 
 static int ngx_http_process_request_line(ngx_http_request_t *r);
 static int ngx_http_process_request_header(ngx_http_request_t *r);
+static int ngx_http_process_request_header_line(ngx_http_request_t *r);
 
-static int ngx_http_process_http_request(ngx_http_request_t *r);
+static int ngx_http_block_read(ngx_event_t *ev);
+static int ngx_http_read_discarded_body(ngx_event_t *ev);
+
+static int ngx_http_handler(ngx_http_request_t *r);
+static int ngx_http_set_default_handler(ngx_http_request_t *r);
+
+static int ngx_http_writer(ngx_event_t *ev);
+
+static int ngx_http_special_response(ngx_http_request_t *r, int error);
+static int ngx_http_redirect(ngx_http_request_t *r, int redirect);
+static int ngx_http_error(ngx_http_request_t *r, int error);
 
 static int ngx_http_close_request(ngx_http_request_t *r);
 static size_t ngx_http_log_error(void *data, char *buf, size_t len);
@@ -54,8 +71,15 @@
 
     ngx_test_null(c->addr_text, ngx_palloc(c->pool, c->addr_textlen),
                   NGX_ERROR);
+#if (WIN32)
+/*
+    c->addr_text = inet_ntoa((struct in_addr) ((char *)c->sockaddr + c->addr));
+*/
+    c->addr_text = NULL;
+#else
     inet_ntop(c->family, (char *)c->sockaddr + c->addr,
               c->addr_text, c->addr_textlen);
+#endif
 
     ngx_test_null(ctx, ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)),
                   NGX_ERROR);
@@ -107,22 +131,22 @@
     r->connection = c;
     r->server = srv;
 
-    /* TODO: request's pool size */
-    ngx_test_null(r->pool, ngx_create_pool(16384, ev->log),
+    ngx_test_null(r->pool, ngx_create_pool(srv->request_pool_size, ev->log),
                   ngx_http_close_request(r));
 
     ngx_test_null(r->header_in,
-                  ngx_create_temp_hunk(r->pool, srv->buff_size, 0, 0),
+                  ngx_create_temp_hunk(r->pool, srv->header_buffer_size, 0, 0),
                   ngx_http_close_request(r));
 
     ev->event_handler = ngx_http_process_request;
     r->state_handler = ngx_http_process_request_line;
+    r->process_header = 1;
 
     return ngx_http_process_request(ev);
 }
 
 
-int ngx_http_process_request(ngx_event_t *ev)
+static int ngx_http_process_request(ngx_event_t *ev)
 {
     int n, rc;
     ngx_connection_t *c ;
@@ -151,11 +175,9 @@
     ngx_log_debug(ev->log, "http read %d" _ n);
 
     if (n == 0) {
-        /* STUB: c-> */
-        if (ev->unexpected_eof)
+        if (c->unexpected_eof)
             ngx_log_error(NGX_LOG_INFO, c->log, 0,
                           "client prematurely closed connection");
-
         return ngx_http_close_request(r);
     }
 
@@ -173,8 +195,9 @@
 
         /* rc == NGX_OK || rc == NGX_AGAIN */
 
-    } while (r->header_in->pos.mem < r->header_in->last.mem);
-             
+    } while (r->process_header
+             && r->header_in->pos.mem < r->header_in->last.mem);
+
     if (!r->header_timeout) {
         r->header_timeout = 1;
         ngx_del_timer(ev);
@@ -200,27 +223,23 @@
         ngx_log_debug(r->connection->log, "HTTP: %d, %d, %s" _
                       r->method _ r->http_version _ r->uri);
 
-        if (r->http_version == 9) {
-            /* set lock event */
-            return ngx_http_process_http_request(r);
-        }
+        if (r->http_version == 9)
+            return ngx_http_handler(r);
 
         r->state_handler = ngx_http_process_request_header;
-        r->connection->read->action = "reading client request headers";
+        ctx = r->connection->log->data;
+        ctx->action = "reading client request headers";
 
         return NGX_OK;
     }
 
-    r->connection->log->handler = NULL;
     ctx = r->connection->log->data;
-
+    r->connection->log->handler = NULL;
     ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                   header_errors[rc - NGX_HTTP_INVALID_METHOD], ctx->client);
-
     r->connection->log->handler = ngx_http_log_error;
 
-    /* STUB return ngx_http_error(r, NGX_HTTP_BAD_REQUEST)  */
-    return ngx_http_close_request(r);
+    return ngx_http_error(r, NGX_HTTP_BAD_REQUEST);
 }
 
 static int ngx_http_process_request_header(ngx_http_request_t *r)
@@ -232,63 +251,192 @@
         rc = ngx_read_http_header_line(r);
 
         if (rc == NGX_OK) {
-            *r->header_name_end = '\0';
-            *r->header_end = '\0';
-            ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _
-                          r->header_name_start _ r->header_start);
+            if (ngx_http_process_request_header_line(r) == NGX_ERROR)
+                return ngx_http_error(r, NGX_HTTP_BAD_REQUEST);
+
+        } else if (rc == NGX_HTTP_HEADER_DONE) {
+            ngx_log_debug(r->connection->log, "HTTP header done");
+            return ngx_http_handler(r);
 
         } else if (rc == NGX_AGAIN) {
             return NGX_AGAIN;
 
-        } else if (rc == NGX_HTTP_HEADER_DONE) {
-            break;
-
         } else if (rc == NGX_HTTP_INVALID_HEADER) {
-            r->connection->log->handler = NULL;
             ctx = r->connection->log->data;
+            r->connection->log->handler = NULL;
             ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
                           "client %s sent invalid header", ctx->client);
             r->connection->log->handler = ngx_http_log_error;
 
-            /* STUB return ngx_http_error(r, NGX_HTTP_BAD_REQUEST)  */
-            return ngx_http_close_request(r);
+            return ngx_http_error(r, NGX_HTTP_BAD_REQUEST);
         }
     }
+}
 
-    r->state_handler = NULL;
-    r->connection->read->action = "reading client request body";
+static int ngx_http_process_request_header_line(ngx_http_request_t *r)
+{
+    /* STUB */
+    *r->header_name_end = '\0';
+    *r->header_end = '\0';
+    ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _
+                  r->header_name_start _ r->header_start);
 
-    r->connection->read->read_discarded = 1;
-    r->connection->read->unexpected_eof = 0;
-    ngx_log_debug(r->connection->log, "HTTP header done");
+    return NGX_OK;
+}
+
+static int ngx_http_block_read(ngx_event_t *ev)
+{
+    ngx_log_debug(ev->log, "http read blocked");
+
+    ngx_del_event(ev, NGX_READ_EVENT);
+    ev->blocked = 1;
+}
+
+void ngx_http_discard_body(ngx_http_request_t *r)
+{
+    ngx_log_debug(r->connection->log, "set discard body");
 
     ngx_del_timer(r->connection->read);
 
-    return ngx_http_process_http_request(r);
+    if (r->client_content_length)
+        r->connection->read->event_handler = ngx_http_read_discarded_body;
 }
 
-#if 0
-static int ngx_http_lock_read(ngx_event_t *ev)
+static int ngx_http_read_discarded_body(ngx_event_t *ev)
 {
-    ngx_del_event(ev, NGX_READ_EVENT);
-    ev->read_blocked = 1;
-}
-#endif
+    size_t   size;
+    ssize_t  n;
+    ngx_connection_t    *c;
+    ngx_http_request_t  *r;
 
-static int ngx_http_process_http_request(ngx_http_request_t *r)
+    c = (ngx_connection_t *) ev->data;
+    r = (ngx_http_request_t *) c->data;
+
+    ngx_log_debug(ev->log, "http read discarded body");
+
+    if (ev->timedout)
+        return NGX_ERROR;
+
+    if (r->discarded_buffer == NULL)
+        ngx_test_null(r->discarded_buffer,
+                      ngx_palloc(r->pool, r->server->discarded_buffer_size),
+                      NGX_ERROR);
+
+    size = r->client_content_length;
+    if (size > r->server->discarded_buffer_size)
+        size = r->server->discarded_buffer_size;
+
+    n = ngx_event_recv(c, r->discarded_buffer, size);
+    if (n > 0)
+        r->client_content_length -= n;
+
+    return n;
+}
+
+static int ngx_http_discarded_read(ngx_event_t *ev)
+{
+    ssize_t n;
+    ngx_connection_t    *c;
+    ngx_http_request_t  *r;
+
+    c = (ngx_connection_t *) ev->data;
+    r = (ngx_http_request_t *) c->data;
+
+    ngx_log_debug(ev->log, "http discarded read");
+
+    if (ev->timedout)
+        return NGX_ERROR;
+
+    if (r->discarded_buffer == NULL)
+        ngx_test_null(r->discarded_buffer,
+                      ngx_palloc(r->pool, r->server->discarded_buffer_size),
+                      NGX_ERROR);
+
+    n = ngx_event_recv(c, r->discarded_buffer,
+                       r->server->discarded_buffer_size);
+
+    return n;
+}
+
+static int ngx_http_handler(ngx_http_request_t *r)
+{
+    int  rc;
+
+    ngx_del_timer(r->connection->read);
+    r->header_timeout = 1;
+
+    r->process_header = 0;
+    r->state_handler = NULL;
+    r->connection->unexpected_eof = 0;
+
+    r->connection->read->event_handler = ngx_http_block_read;
+
+    /* STUB: should find handler */
+    r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
+    rc = ngx_http_set_default_handler(r);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
+        return ngx_http_special_response(r, rc);
+
+    rc = r->handler(r);
+
+    /* transfer not completed */
+    if (rc == NGX_AGAIN) {
+#if (HAVE_CLEAR_EVENT)
+        if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
+                          NGX_CLEAR_EVENT) == NGX_ERROR) {
+#else
+        if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
+                          NGX_ONESHOT_EVENT) == NGX_ERROR) {
+#endif
+            /* log http request */
+            return ngx_http_close_request(r);
+        }
+
+        ngx_add_timer(r->connection->write, 5000);
+
+        r->connection->write->event_handler = ngx_http_writer;
+        return rc;
+    }
+
+    if (rc == NGX_ERROR) {
+        /* log http request */
+        return ngx_http_close_request(r);
+    }
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
+        return ngx_http_special_response(r, rc);
+
+    /* rc == NGX_OK */
+
+    /* STUB */
+    return ngx_http_close_request(r);
+
+/*
+    if (!keepalive)
+        if (linger)
+            set linger timeout on read
+            shutdown socket
+        else
+            close socket
+*/
+}
+
+static int ngx_http_set_default_handler(ngx_http_request_t *r)
 {
     int   err, rc;
     char *name, *loc, *file;
 
-    ngx_log_debug(r->connection->log, "HTTP request");
-
     ngx_test_null(r->headers_out,
                   ngx_pcalloc(r->pool, sizeof(ngx_http_headers_out_t)),
-                  ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR));
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
 
     if (*(r->uri_end - 1) == '/') {
-        r->handler = NGX_HTTP_DIRECTORY_HANDLER;
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+#if 0
+        r->handler = ngx_http_index_handler;
         return NGX_OK;
+#endif
     }
 
     /* 20 bytes is spare space for some index name, i.e. index.html */
@@ -296,7 +444,7 @@
 
     ngx_test_null(r->filename,
                   ngx_palloc(r->pool, r->filename_len),
-                  ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR));
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
 
     r->location = ngx_cpystrn(r->filename, r->server->doc_root,
                               r->server->doc_root_len);
@@ -305,99 +453,73 @@
 
     ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->filename);
 
-    if (ngx_file_type(r->filename, &r->file_info) == -1) {
+    if (ngx_file_type(r->filename, &r->fileinfo) == -1) {
         err = ngx_errno;
         ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                     "ngx_process_http_request: "
                       ngx_file_type_n " %s failed", r->filename);
 
         if (err == NGX_ENOENT)
-            return ngx_http_error(r, NGX_HTTP_NOT_FOUND);
+            return NGX_HTTP_NOT_FOUND;
         else
-            return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (ngx_is_dir(r->file_info)) {
+    if (ngx_is_dir(r->fileinfo)) {
         ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->filename);
         *file++ = '/';
         *file = '\0';
         r->headers_out->location = r->location;
-        return ngx_http_redirect(r, NGX_HTTP_MOVED_PERMANENTLY);
+        return NGX_HTTP_MOVED_PERMANENTLY;
     }
 
-    /* STUB */
-    rc =  ngx_http_static_handler(r);
-    if (rc == 0) {
-        r->connection->write->event_handler = ngx_http_writer;
-        ngx_add_event(r->connection->write, NGX_WRITE_EVENT, NGX_CLEAR_EVENT);
-    }
-    return rc;
+    r->handler = ngx_http_static_handler;
 
-    r->handler = NGX_HTTP_STATIC_HANDLER;
     return NGX_OK;
 }
 
-#if 0
-
-static int ngx_http_handler(ngx_http_request_t *r)
-{
-    find_http_handler();
-
-    if (r->discard_body && r->connection->read->ready)
-        ngx_http_discarad_body();
-
-    rc = http_handler();
-
-    /* transfer not completed */
-    if (rc == NGX_AGAIN)
-        return rc;
-
-    if (rc == NGX_ERROR) {
-        log http request
-        close http request
-        return rc;
-    }
-
-    if (rc > 300) {
-        send special response
-    }
-
-    /* rc == NGX_OK */
-
-    if (!keepalive)
-        if (linger)
-            set linger timeout on read
-            shutdown socket
-        else
-            close socket
-
-    log http request
-    close http request
-    if (keepalive)
-        return NGX_OK;
-    else
-        close connection
-        return NGX_OK;
-}
 
 static int ngx_http_writer(ngx_event_t *ev)
 {
     int rc;
+    unsigned int timeout;
+    ngx_connection_t    *c;
+    ngx_http_request_t  *r;
 
-    ngx_connection_t   *c = (ngx_connection_t *) ev->data;
-    ngx_http_request_t *r = (ngx_http_request_t *) c->data;
+    c = (ngx_connection_t *) ev->data;
+    r = (ngx_http_request_t *) c->data;
 
-    rc = ngx_http_filter(r, NULL);
+    rc = ngx_http_output_filter(r, NULL);
 
-    if (rc == NGX_AGAIN)
+    ngx_log_debug(ev->log, "output_filter: %d" _ rc);
+
+    if (rc == NGX_AGAIN) {
+
+        if (c->sent > 0) {
+            ngx_log_debug(ev->log, "sent: " QD_FMT _ c->sent);
+            timeout = (ngx_msec_t) (c->sent * 10);
+            ngx_log_debug(ev->log, "timeout: %d" _ timeout);
+            ngx_del_timer(ev);
+            ngx_add_timer(ev, timeout);
+        }
+
+        if (ev->oneshot)
+            if (ngx_add_event(r->connection->write, NGX_WRITE_EVENT,
+                              NGX_ONESHOT_EVENT) == NGX_ERROR) {
+            /* log http request */
+            return ngx_http_close_request(r);
+        }
+
         return rc;
+    }
 
     if (rc == NGX_ERROR)
         return rc;
 
     /* rc == NGX_OK */
 
+    return ngx_http_close_request(r);
 
+/*
     if (!keepalive)
         if (linger)
             shutdown socket
@@ -411,19 +533,10 @@
     else
         close connection
         return NGX_OK;
+*/
 }
 
-static int ngx_http_discarded_read(ngx_event_t *ev)
-{
-    if (ev->timedout)
-        return NGX_ERROR;
-
-    while (full) {
-        recv();
-    }
-
-    return NGX_OK;
-}
+#if 0
 
 static int ngx_http_keepalive_handler(ngx_event_t *ev)
 {
@@ -446,40 +559,28 @@
 #endif
 
 
-static int ngx_http_writer(ngx_event_t *ev)
+static int ngx_http_special_response(ngx_http_request_t *r, int error)
 {
-    int rc;
-    ngx_connection_t   *c = (ngx_connection_t *) ev->data;
-    ngx_http_request_t *r = (ngx_http_request_t *) c->data;
-
-    rc = ngx_http_write_filter(r, NULL);
-    ngx_log_debug(r->connection->log, "write_filter: %d" _ rc);
-    return rc;
-}
-
-static int ngx_http_handler(ngx_http_request_t *r, int handler)
-{
-    if (handler == NGX_HTTP_STATIC_HANDLER) 
-        return ngx_http_static_handler(r);
-
-#if 0
-    elsif (handler == NGX_HTTP_DIRECTORY_HANDLER) 
-        return ngx_http_index_handler(r);
-#endif
-
-    return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    return ngx_http_error(r, error);
 }
 
 static int ngx_http_redirect(ngx_http_request_t *r, int redirect)
 {
     /* STUB */
-    return -1;
+
+    /* log request */
+
+    return ngx_http_close_request(r);
 }
 
 static int ngx_http_error(ngx_http_request_t *r, int error)
 {
     /* STUB */
-    return -1;
+    ngx_log_debug(r->connection->log, "http error: %d" _ error);
+
+    /* log request */
+
+    return ngx_http_close_request(r);
 }
 
 #if 0
@@ -549,8 +650,8 @@
 
     ngx_log_debug(r->connection->log, "http close");
 
-    ngx_del_event(r->connection->read, NGX_TIMER_EVENT);
-    ngx_del_event(r->connection->write, NGX_TIMER_EVENT);
+    ngx_del_timer(r->connection->read);
+    ngx_del_timer(r->connection->write);
 
     return NGX_ERROR;
 }
@@ -559,6 +660,7 @@
 static size_t ngx_http_log_error(void *data, char *buf, size_t len)
 {
     ngx_http_log_ctx_t *ctx = (ngx_http_log_ctx_t *) data;
+
     if (ctx->url)
         return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
                             ctx->action, ctx->client, ctx->url);
diff --git a/src/http/ngx_http_filter.c b/src/http/ngx_http_filter.c
deleted file mode 100644
index 6f39d9b..0000000
--- a/src/http/ngx_http_filter.c
+++ /dev/null
@@ -1,236 +0,0 @@
-
-
-#include <ngx_hunk.h>
-#include <ngx_http.h>
-#include <ngx_http_filter.h>
-
-
-ngx_http_module_t  ngx_http_filter_module;
-
-
-/* STUB */
-static ngx_http_filter_ctx_t module_ctx;
-
-void ngx_http_filter_init()
-{
-     module_ctx.hunk_size = 32 * 1024;
-     module_ctx.out.hunk = NULL;
-     module_ctx.out.next = NULL;
-     module_ctx.next_filter = ngx_http_write_filter;
-
-     ngx_http_filter_module.ctx = &module_ctx;
-}
-/* */
-
-
-/*
-int ngx_http_filter(ngx_http_request_t *r, ngx_chain_t *in)
-*/
-
-/*
-    flags NGX_HUNK_RECYCLED, NGX_HUNK_FLUSH, NGX_HUNK_LAST
-*/
-
-int ngx_http_filter(ngx_http_request_t *r, ngx_hunk_t *hunk)
-{
-    int      rc;
-    size_t   size;
-    ssize_t  n;
-    ngx_chain_t  *ce;
-    ngx_http_filter_ctx_t  *ctx;
-
-    ctx = (ngx_http_filter_ctx_t *)
-                              ngx_get_module_ctx(r->main ? r->main : r,
-                                                      &ngx_http_filter_module);
-
-    if (hunk && (hunk->type & NGX_HUNK_LAST))
-        ctx->last = 1;
-
-    /* input chain is not empty */
-    if (ctx->in) {
-
-        while (ctx->in) {
-
-            /* add hunk to input chain */
-            if (hunk) {
-                for (ce = ctx->in; ce->next; ce = ce->next)
-                    /* void */ ;
-
-                ngx_add_hunk_to_chain(ce->next, hunk, r->pool,
-                                      NGX_ERROR);
-            }
-
-            /* our hunk is still busy */
-            if (ctx->hunk->pos.mem < ctx->hunk->last.mem) {
-                rc = ctx->next_filter(r, NULL);
-
-            /* our hunk is free */
-            } else {
-                ctx->out.hunk = ctx->hunk;
-
-                rc = ngx_http_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
-#if (NGX_FILE_AIO)
-                if (rc == NGX_AGAIN)
-                    return rc;
-#endif
-                if (rc == NGX_ERROR)
-                    return rc;
-
-                /* whole hunk is copied so we send to next filter chain part
-                   up to next hunk that need to be copied */
-                if (ctx->in->hunk->pos.mem == ctx->in->hunk->last.mem) {
-                    ctx->out.next = ctx->in->next;
-
-                    for (ce = ctx->in->next; ce; ce = ce->next) {
-                        if (ce->type & NGX_HUNK_FILE)
-                            break;
-
-                        if ((ce->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP)
-                            && (r->filter & NGX_HTTP_FILTER_NEED_TEMP))
-                            break;
-                    }
-
-                    ctx->out.next = ce;
-
-                } else {
-                    ctx->out.next = NULL;
-                }
-
-                rc = ctx->next_filter(r, &ctx->out);
-            }
-
-            if (rc == NGX_OK)
-                ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
-            else
-                return rc;
-        }
-
-    /* input chain is empty */
-    } else {
-
-        if (hunk == NULL) {
-            rc = ctx->next_filter(r, NULL);
-
-        } else {
-
-            /* we need to copy hunk to our hunk */
-            if (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)
-                    && (hunk->type & NGX_HUNK_FILE))
-                || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP)
-                    && (hunk->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP))
-               ) {
-
-                /* out hunk is still busy */
-                if (ctx->hunk && ctx->hunk->pos.mem < ctx->hunk->last.mem) {
-                    ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
-                                          NGX_ERROR);
-
-                    rc = ctx->next_filter(r, NULL);
-
-                } else {
-                    if (ctx->hunk == NULL) {
-
-                        if (hunk->type & NGX_HUNK_LAST) {
-                            size = hunk->last.mem - hunk->pos.mem;
-                            if (size > ctx->hunk_size)
-                                size = ctx->hunk_size;
-
-                        } else {
-                            size = ctx->hunk_size;
-                        }
-
-                        ngx_test_null(ctx->hunk,
-                                      ngx_create_temp_hunk(r->pool, size,
-                                                           50, 50),
-                                      NGX_ERROR);
-
-                        rc = ngx_http_filter_copy_hunk(ctx->hunk,
-                                                       ctx->in->hunk);
-#if (NGX_FILE_AIO)
-                        if (rc == NGX_AGAIN) {
-                            /* add hunk to input chain */
-                            ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
-                                                  NGX_ERROR);
-
-                            return rc;
-                        }
-#endif
-                        if (rc == NGX_ERROR)
-                            return rc;
-
-                        if (ctx->in->hunk->pos.mem < ctx->in->hunk->last.mem)
-                            ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
-                                                  NGX_ERROR);
-
-                        ctx->out.hunk = ctx->hunk;
-                        ctx->out.next = NULL;
-
-                        rc = ctx->next_filter(r, &ctx->out);
-                    }
-                }
-
-            } else {
-                ctx->out.hunk = hunk;
-                ctx->out.next = NULL;
-
-                rc = ctx->next_filter(r, &ctx->out);
-
-            }
-        }
-    }
-
-    if (rc == NGX_OK && ctx->last) {
-        /* STUB */
-        return NGX_ERROR;
-    }
-
-    if (rc == NGX_OK) {
-        ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
-#if level_event
-        ngx_del_event(r->connection->write, NGX_WRITE_EVENT);
-#endif
-    }
-
-    return rc;
-}
-
-
-int ngx_http_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src, ngx_log_t *log)
-{
-    size_t  size;
-
-    size = hunk->last.mem - hunk->pos.mem;
-    if (size > dst->end - dst->pos.mem)
-        size = dst->end - dst->pos.mem;
-
-    if (src->type & NGX_HUNK_FILE) {
-        n = ngx_read_file(src->handle, dst->pos.mem, size);
-
-        if (n == NGX_ERROR) {
-            ngx_log_error(NGX_LOG_ERR, log, ngx_errno,
-                          ngx_read_file_n " failed for client");
-            return n;
-
-#if (NGX_FILE_AIO)
-        } else if (n == NGX_AGAIN) {
-            return n;
-#endif
-
-        } else {
-            ngx_assert((n == size), /* void */ ; , log,
-                       ngx_read_file_n " reads only %d of %d for client" _
-                       n _ size);
-        }
-
-        src->pos.mem += n;
-        dst->last.mem += n;
-
-    } else {
-        ngx_memcpy(src->pos.mem, dst->pos.mem, size);
-
-        src->pos.mem += size;
-        dst->last.mem += size;
-    }
-
-    return NGX_OK;
-}
diff --git a/src/http/ngx_http_output_filter.c b/src/http/ngx_http_output_filter.c
new file mode 100644
index 0000000..693b399
--- /dev/null
+++ b/src/http/ngx_http_output_filter.c
@@ -0,0 +1,253 @@
+
+
+#include <ngx_core.h>
+#include <ngx_files.h>
+#include <ngx_string.h>
+#include <ngx_hunk.h>
+#include <ngx_http.h>
+#include <ngx_http_output_filter.h>
+
+
+/* STUB */
+int ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in);
+
+
+
+static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src);
+
+ngx_http_module_t  ngx_http_output_filter_module;
+
+
+/* STUB */
+static ngx_http_output_filter_ctx_t module_ctx;
+
+void ngx_http_output_filter_init()
+{
+     module_ctx.hunk_size = 32 * 1024;
+     module_ctx.out.hunk = NULL;
+     module_ctx.out.next = NULL;
+     module_ctx.next_filter = ngx_http_write_filter;
+
+     ngx_http_output_filter_module.ctx = &module_ctx;
+}
+/* */
+
+
+/*
+    flags NGX_HUNK_RECYCLED, NGX_HUNK_FLUSH, NGX_HUNK_LAST
+*/
+
+int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk)
+{
+    int      rc, first;
+    size_t   size;
+    ssize_t  n;
+    ngx_chain_t  *ce;
+    ngx_http_output_filter_ctx_t  *ctx;
+
+    ctx = (ngx_http_output_filter_ctx_t *)
+                              ngx_get_module_ctx(r->main ? r->main : r,
+                                               &ngx_http_output_filter_module);
+
+    if (hunk && (hunk->type & NGX_HUNK_LAST))
+        ctx->last = 1;
+
+    first = 1;
+
+    while (first || ctx->in) {
+
+         /* input chain is not empty */
+        if (ctx->in) {
+
+            /* add hunk to input chain */
+            if (first && hunk) {
+                for (ce = ctx->in; ce->next; ce = ce->next)
+                    /* void */ ;
+
+                ngx_add_hunk_to_chain(ce->next, hunk, r->pool, NGX_ERROR);
+            }
+
+            first = 0;
+
+            /* our hunk is still busy */
+            if (ctx->hunk->pos.mem < ctx->hunk->last.mem) {
+                rc = ctx->next_filter(r, NULL);
+
+            /* our hunk is free */
+            } else {
+                ctx->out.hunk = ctx->hunk;
+
+                rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
+#if (NGX_FILE_AIO)
+                if (rc == NGX_AGAIN)
+                    return rc;
+#endif
+                if (rc == NGX_ERROR)
+                    return rc;
+
+                /* whole hunk is copied so we send to next filter chain part
+                   up to next hunk that need to be copied */
+                if (ctx->in->hunk->pos.mem == ctx->in->hunk->last.mem) {
+                    ctx->out.next = ctx->in->next;
+
+                    for (ce = ctx->in->next; ce; ce = ce->next) {
+                        if (ce->hunk->type & NGX_HUNK_FILE)
+                            break;
+
+                        if ((ce->hunk->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP)
+                            && (r->filter & NGX_HTTP_FILTER_NEED_TEMP))
+                            break;
+                    }
+
+                    ctx->out.next = ce;
+
+                } else {
+                    ctx->out.next = NULL;
+                }
+
+                rc = ctx->next_filter(r, &ctx->out);
+            }
+
+            /* delete completed hunks from input chain */
+            for (ce = ctx->in; ce; ce = ce->next) {
+                 if (ce->hunk->pos.file == ce->hunk->last.file)
+                     ctx->in = ce->next;
+            }
+
+            if (rc == NGX_OK)
+                ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
+            else
+                return rc;
+
+        /* input chain is empty */
+        } else {
+
+            first = 0;
+
+            if (hunk == NULL) {
+                rc = ctx->next_filter(r, NULL);
+
+            } else {
+
+                /* we need to copy hunk to our hunk */
+                if (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)
+                        && (hunk->type & NGX_HUNK_FILE))
+                    || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP)
+                        && (hunk->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP))
+                   ) {
+
+                    /* out hunk is still busy */
+                    if (ctx->hunk && ctx->hunk->pos.mem < ctx->hunk->last.mem) {
+                        ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
+                                              NGX_ERROR);
+
+                        rc = ctx->next_filter(r, NULL);
+
+                    } else {
+                        if (ctx->hunk == NULL) {
+
+                            if (hunk->type & NGX_HUNK_LAST) {
+                                size = hunk->last.mem - hunk->pos.mem;
+                                if (size > ctx->hunk_size)
+                                    size = ctx->hunk_size;
+
+                            } else {
+                                size = ctx->hunk_size;
+                            }
+
+                            ngx_test_null(ctx->hunk,
+                                          ngx_create_temp_hunk(r->pool, size,
+                                                               50, 50),
+                                          NGX_ERROR);
+                            ctx->hunk->type |= NGX_HUNK_RECYCLED;
+
+                            rc = ngx_http_output_filter_copy_hunk(ctx->hunk,
+                                                                  hunk);
+#if (NGX_FILE_AIO)
+                            if (rc == NGX_AGAIN) {
+                                /* add hunk to input chain */
+                                ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
+                                                      NGX_ERROR);
+
+                                return rc;
+                            }
+#endif
+                            if (rc == NGX_ERROR)
+                                return rc;
+
+                            if (hunk->pos.mem < hunk->last.mem)
+                                ngx_add_hunk_to_chain(ctx->in, hunk, r->pool,
+                                                      NGX_ERROR);
+
+                            ctx->out.hunk = ctx->hunk;
+                            ctx->out.next = NULL;
+
+                            rc = ctx->next_filter(r, &ctx->out);
+                        }
+                    }
+
+                } else {
+                    ctx->out.hunk = hunk;
+                    ctx->out.next = NULL;
+
+                    rc = ctx->next_filter(r, &ctx->out);
+                }
+            }
+        }
+
+        if (rc == NGX_OK && ctx->hunk)
+            ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
+    }
+
+    if (rc == NGX_OK && ctx->last)
+        return NGX_OK;
+
+    if (rc == NGX_OK) {
+        ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
+#if level_event
+        ngx_del_event(r->connection->write, NGX_WRITE_EVENT);
+#endif
+    }
+
+    return rc;
+}
+
+
+static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src)
+{
+    size_t   size;
+    ssize_t  n;
+
+    size = src->last.mem - src->pos.mem;
+    if (size > dst->end - dst->pos.mem)
+        size = dst->end - dst->pos.mem;
+
+    if (src->type & NGX_HUNK_FILE) {
+        n = ngx_read_file(src->file, dst->pos.mem, size, src->pos.file);
+
+        if (n == NGX_ERROR) {
+            return n;
+
+#if (NGX_FILE_AIO)
+        } else if (n == NGX_AGAIN) {
+            return n;
+#endif
+
+        } else {
+            ngx_assert((n == size), /* void */ ; , src->file->log,
+                       ngx_read_file_n " reads only %d of %d" _
+                       n _ size);
+        }
+
+        src->pos.mem += n;
+        dst->last.mem += n;
+
+    } else {
+        ngx_memcpy(src->pos.mem, dst->pos.mem, size);
+
+        src->pos.mem += size;
+        dst->last.mem += size;
+    }
+
+    return NGX_OK;
+}
diff --git a/src/http/ngx_http_filter.h b/src/http/ngx_http_output_filter.h
similarity index 65%
rename from src/http/ngx_http_filter.h
rename to src/http/ngx_http_output_filter.h
index 0f738cd..072e0bd 100644
--- a/src/http/ngx_http_filter.h
+++ b/src/http/ngx_http_output_filter.h
@@ -1,5 +1,5 @@
-#ifndef _NGX_HTTP_FILTER_H_INCLUDED_
-#define _NGX_HTTP_FILTER_H_INCLUDED_
+#ifndef _NGX_HTTP_OUTPUT_FILTER_H_INCLUDED_
+#define _NGX_HTTP_OUTPUT_FILTER_H_INCLUDED_
 
 
 #include <ngx_core.h>
@@ -14,7 +14,7 @@
     ngx_chain_t   out;
     size_t        hunk_size;
     unsigned      last;
-} ngx_http_filter_ctx_t;
+} ngx_http_output_filter_ctx_t;
 
 
-#endif /* _NGX_HTTP_FILTER_H_INCLUDED_ */
+#endif /* _NGX_HTTP_OUTPUT_FILTER_H_INCLUDED_ */
diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c
index 2ccbe2e..dcb74c9 100644
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -2,9 +2,9 @@
 #include <ngx_config.h>
 
 #include <ngx_hunk.h>
-#include <ngx_http.h>
-#include <ngx_http_filter.h>
 #include <ngx_event_write.h>
+#include <ngx_http.h>
+#include <ngx_http_output_filter.h>
 
 #include <ngx_http_write_filter.h>
 
@@ -48,7 +48,7 @@
                       ch->hunk->type _ ch->hunk->pos.file _
                       ch->hunk->last.file - ch->hunk->pos.file);
 
-        if (ch->hunk->type & NGX_HUNK_FLUSH)
+        if (ch->hunk->type & NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)
             flush = size;
 
         if (ch->hunk->type & NGX_HUNK_LAST)
@@ -69,7 +69,7 @@
                       ch->hunk->type _ ch->hunk->pos.file _
                       ch->hunk->last.file - ch->hunk->pos.file);
 
-        if (ch->hunk->type & NGX_HUNK_FLUSH)
+        if (ch->hunk->type & NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)
             flush = size;
 
         if (ch->hunk->type & NGX_HUNK_LAST)
@@ -85,5 +85,7 @@
 
     ctx->out = chain;
 
+    ngx_log_debug(r->connection->log, "write filter %x" _ chain);
+
     return (chain ? NGX_AGAIN : NGX_OK);
 }
diff --git a/src/http/ngx_http_write_filter.h b/src/http/ngx_http_write_filter.h
index 6a2c6f2..0b3fa54 100644
--- a/src/http/ngx_http_write_filter.h
+++ b/src/http/ngx_http_write_filter.h
@@ -7,5 +7,7 @@
     size_t        buffer_output;
 } ngx_http_write_filter_ctx_t;
 
+int ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in);
+
 
 #endif /* _NGX_HTTP_WRITE_FILTER_H_INCLUDED_ */