changeset 8:708f8bb772ec

nginx-0.0.1-2002-09-02-18:48:24 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 02 Sep 2002 14:48:24 +0000
parents b5481d6fbbd4
children 6f58641241bb
files src/core/nginx.c src/core/ngx_config.h src/core/ngx_connection.h src/core/ngx_file.h src/core/ngx_hunk.c src/core/ngx_hunk.h src/core/ngx_log.c src/core/ngx_log.h src/event/modules/ngx_kqueue_module.c src/event/modules/ngx_kqueue_module.h src/event/modules/ngx_select_module.c src/event/modules/ngx_select_module.h src/event/ngx_event.c src/event/ngx_event.h src/event/ngx_event_accept.c src/event/ngx_event_write.c src/http/modules/ngx_http_header_filter.c src/http/modules/ngx_http_static_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_event.c src/http/ngx_http_filter.c src/http/ngx_http_filter.h src/http/ngx_http_output_filter.c src/http/ngx_http_output_filter.h src/http/ngx_http_write_filter.c src/http/ngx_http_write_filter.h src/os/unix/freebsd/ngx_sendfile.c src/os/unix/ngx_file.c src/os/unix/ngx_file.h src/os/unix/ngx_files.c src/os/unix/ngx_files.h src/os/unix/ngx_sendfile.h src/os/unix/ngx_sendv.c src/os/unix/ngx_time.h src/os/win32/ngx_errno.h src/os/win32/ngx_file.h src/os/win32/ngx_files.c src/os/win32/ngx_files.h src/os/win32/ngx_sendfile.c src/os/win32/ngx_sendfile.h src/os/win32/ngx_socket.h src/os/win32/ngx_time.h src/os/win32/ngx_types.h
diffstat 39 files changed, 703 insertions(+), 562 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -36,8 +36,6 @@ ngx_array_t  *ngx_listening_sockets;
 
 int main(int argc, char *const *argv)
 {
-    int  i;
-
     /* STUB */
     ngx_log.log_level = NGX_LOG_DEBUG;
 
@@ -68,6 +66,8 @@ int main(int argc, char *const *argv)
 
     /* STUB */
     ngx_worker(&ngx_log);
+
+    return 0;
 }
 
 static void ngx_open_listening_sockets(ngx_log_t *log)
--- a/src/core/ngx_config.h
+++ b/src/core/ngx_config.h
@@ -18,6 +18,7 @@
 
 #include <winsock2.h>
 #include <mswsock.h>
+#include <stddef.h>    /* offsetof */
 #include <stdio.h>
 #include <stdarg.h>
 
@@ -88,6 +89,10 @@
 #endif
 
 
+#ifndef HAVE_SELECT
+#define HAVE_SELECT 1
+#endif
+
 
 #ifdef __FreeBSD__
 
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -21,6 +21,8 @@ struct ngx_connection_s {
     ngx_event_t      *write;
 #endif
 
+    off_t             sent;
+
     ngx_log_t        *log;
     int             (*handler)(ngx_connection_t *c);
     ngx_server_t     *server;
@@ -35,6 +37,8 @@ struct ngx_connection_s {
     size_t            addr_textlen;
 
     unsigned int      post_accept_timeout;
+
+    unsigned          unexpected_eof:1;
 };
 
 
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_file.h
@@ -0,0 +1,16 @@
+#ifndef _NGX_FILE_H_INCLUDED_
+#define _NGX_FILE_H_INCLUDED_
+
+
+#include <ngx_files.h>
+#include <ngx_log.h>
+
+typedef struct ngx_file_s  ngx_file_t;
+
+struct ngx_file_s {
+    ngx_fd_t      fd;
+    ngx_log_t    *log;
+};
+
+
+#endif _NGX_FILE_H_INCLUDED_
--- a/src/core/ngx_hunk.c
+++ b/src/core/ngx_hunk.c
@@ -1,13 +1,13 @@
 
-#include <ngx_file.h>
 #include <ngx_hunk.h>
 
 
-ngx_hunk_t *ngx_get_hunk(ngx_pool_t *pool, int size, int before, int after)
+ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size,
+                                 int before, int after)
 {
     ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t));
 
-#ifndef OFF_EQUAL_PTR
+#if !(HAVE_OFFSET_EQUAL_PTR)
     h->pos.file = h->last.file = 0;
 #endif
 
@@ -18,16 +18,16 @@ ngx_hunk_t *ngx_get_hunk(ngx_pool_t *poo
 
     h->type = NGX_HUNK_TEMP;
     h->tag = 0;
-    h->fd = (ngx_fd_t) -1;
+    h->file = NULL;
 
     return h;
 }
     
-ngx_hunk_t *ngx_get_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
+ngx_hunk_t *ngx_create_hunk_before(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
 {    
     ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t));
 
-#ifndef OFF_EQUAL_PTR
+#if !(HAVE_OFFSET_EQUAL_PTR)
     h->pos.file = h->last.file = 0;
 #endif
  
@@ -39,7 +39,7 @@ ngx_hunk_t *ngx_get_hunk_before(ngx_pool
 
         h->type = NGX_HUNK_TEMP;
         h->tag = 0;
-        h->fd = (ngx_fd_t) -1;
+        h->file = NULL;
 
     } else {
         h->pre_start = h->start = h->pos.mem = h->last.mem
@@ -48,17 +48,17 @@ ngx_hunk_t *ngx_get_hunk_before(ngx_pool
 
         h->type = NGX_HUNK_TEMP;
         h->tag = 0;
-        h->fd = (ngx_fd_t) -1;
+        h->file = NULL;
     }
 
     return h;
 }
 
-ngx_hunk_t *ngx_get_hunk_after(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
+ngx_hunk_t *ngx_create_hunk_after(ngx_pool_t *pool, ngx_hunk_t *hunk, int size)
 {
     ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t));
 
-#ifndef OFF_EQUAL_PTR
+#if !(HAVE_OFFSET_EQUAL_PTR)
     h->pos.file = h->last.file = 0;
 #endif
 
@@ -71,7 +71,7 @@ ngx_hunk_t *ngx_get_hunk_after(ngx_pool_
                                                                 hunk->last.mem;
         h->type = NGX_HUNK_TEMP;
         h->tag = 0;
-        h->fd = (ngx_fd_t) -1;
+        h->file = NULL;
 
     } else {
         h->pre_start = h->start = h->pos.mem = h->last.mem =
@@ -80,7 +80,7 @@ ngx_hunk_t *ngx_get_hunk_after(ngx_pool_
 
         h->type = NGX_HUNK_TEMP;
         h->tag = 0;
-        h->fd = (ngx_fd_t) -1;
+        h->file = NULL;
     }
 
     return h;
--- a/src/core/ngx_hunk.h
+++ b/src/core/ngx_hunk.h
@@ -27,6 +27,8 @@
 /* can be used with NGX_HUNK_LAST only */
 #define NGX_HUNK_SHUTDOWN   0x0400
 
+#define NGX_HUNK_RECYCLED   0x0800
+
 
 #define NGX_HUNK_IN_MEMORY  (NGX_HUNK_TEMP|NGX_HUNK_MEMORY|NGX_HUNK_MMAP)
 
@@ -48,7 +50,7 @@ struct ngx_hunk_s {
     char        *pre_start;     /* start of pre-allocated hunk */
     char        *post_end;      /* end of post-allocated hunk */
     int          tag;
-    ngx_fd_t     fd;
+    ngx_file_t  *file;
 };
 
 typedef struct ngx_chain_s  ngx_chain_t;
@@ -57,8 +59,11 @@ struct ngx_chain_s {
     ngx_chain_t *next;
 };
 
-#define ngx_create_temp_hunk(pool, size, before, after)                      \
-            ngx_get_hunk(pool, size, before, after)
+
+ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size,
+                                 int before, int after);
+
+#define ngx_create_chain_entry(pool) ngx_palloc(pool, sizeof(ngx_chain_t))
 
 #define ngx_add_hunk_to_chain(chain, h, pool, error)                         \
             do {                                                             \
@@ -70,7 +75,6 @@ struct ngx_chain_s {
 
 
 
-ngx_hunk_t *ngx_get_hunk(ngx_pool_t *pool, int size, int before, int after);
 
 
 #endif /* _NGX_CHUNK_H_INCLUDED_ */
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -45,7 +45,11 @@ void ngx_log_error_core(int level, ngx_l
                         " [%s] ", err_levels[level]);
 
     len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1,
+#if (WIN32)
+                        "%d#%d: ", 0, 0);
+#else
                         "%d#%d: ", getpid(), 0);
+#endif
 
 #if (HAVE_VARIADIC_MACROS)
     va_start(args, fmt);
--- a/src/core/ngx_log.h
+++ b/src/core/ngx_log.h
@@ -3,7 +3,7 @@
 
 
 #include <ngx_errno.h>
-#include <ngx_file.h>
+#include <ngx_files.h>
 
 typedef enum {
     NGX_LOG_EMERG = 0,
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -19,7 +19,6 @@
 #error "kqueue is not supported on this platform"
 #endif
 
-static void ngx_add_timer_core(ngx_event_t *ev, u_int timer);
 
 
 static int              kq;
@@ -50,6 +49,7 @@ void ngx_kqueue_init(int max_connections
 #if !(USE_KQUEUE)
     ngx_event_actions.add = ngx_kqueue_add_event;
     ngx_event_actions.del = ngx_kqueue_del_event;
+    ngx_event_actions.timer = ngx_kqueue_add_timer;
     ngx_event_actions.process = ngx_kqueue_process_events;
 #endif
 
@@ -57,21 +57,11 @@ void ngx_kqueue_init(int max_connections
 
 int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags)
 {
-    if (event == NGX_TIMER_EVENT) {
-        ngx_add_timer_core(ev, flags);
-        return 0;
-    }
-
     return ngx_kqueue_set_event(ev, event, EV_ADD | flags);
 }
 
 int ngx_kqueue_del_event(ngx_event_t *ev, int event)
 {
-    if (event == NGX_TIMER_EVENT) {
-        ngx_del_timer(ev);
-        return 0;
-    }
-
     return ngx_kqueue_set_event(ev, event, EV_DELETE);
 }
 
@@ -156,14 +146,9 @@ int ngx_kqueue_process_events(ngx_log_t 
                 delta -= ev->timer_delta;
                 nx = ev->timer_next;
                 ngx_del_timer(ev);
-#if 1
                 ev->timedout = 1;
                 if (ev->event_handler(ev) == NGX_ERROR)
                     ev->close_handler(ev);
-#else
-                if (ev->timer_handler(ev) == -1)
-                    ev->close_handler(ev);
-#endif
                 ev = nx;
             }
 
@@ -182,7 +167,8 @@ int ngx_kqueue_process_events(ngx_log_t 
 
         if (event_list[i].flags & EV_ERROR) {
             ngx_log_error(NGX_LOG_ALERT, log, event_list[i].data,
-                          "ngx_kqueue_process_events: kevent error");
+                          "ngx_kqueue_process_events: kevent error on %d",
+                          event_list[i].ident);
             continue;
         }
 
@@ -215,10 +201,12 @@ int ngx_kqueue_process_events(ngx_log_t 
     return 0;
 }
 
-static void ngx_add_timer_core(ngx_event_t *ev, u_int timer)
+void ngx_kqueue_add_timer(ngx_event_t *ev, ngx_msec_t timer)
 {
     ngx_event_t *e;
 
+    ngx_log_debug(ev->log, "set timer: %d" _ timer);
+
     for (e = timer_queue.timer_next;
          e != &timer_queue && timer > e->timer_delta;
          e = e->timer_next)
@@ -232,19 +220,3 @@ static void ngx_add_timer_core(ngx_event
     e->timer_prev->timer_next = ev;
     e->timer_prev = ev;
 }
-
-#if 0
-static void ngx_inline ngx_del_timer(ngx_event_t *ev)
-{
-    if (ev->timer_prev)
-        ev->timer_prev->timer_next = ev->timer_next;
-
-    if (ev->timer_next) {
-        ev->timer_next->timer_prev = ev->timer_prev;
-        ev->timer_next = NULL;
-    }
-
-    if (ev->timer_prev)
-        ev->timer_prev = NULL;
-}
-#endif
--- a/src/event/modules/ngx_kqueue_module.h
+++ b/src/event/modules/ngx_kqueue_module.h
@@ -10,6 +10,7 @@ void ngx_kqueue_init(int max_connections
 int ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags);
 int ngx_kqueue_del_event(ngx_event_t *ev, int event);
 int ngx_kqueue_set_event(ngx_event_t *ev, int filter, u_int flags);
+void ngx_kqueue_add_timer(ngx_event_t *ev, ngx_msec_t timer);
 int ngx_kqueue_process_events(ngx_log_t *log);
 
 
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -1,5 +1,6 @@
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_types.h>
 #include <ngx_log.h>
 #include <ngx_time.h>
@@ -7,10 +8,10 @@
 #include <ngx_event.h>
 #include <ngx_select_module.h>
 
-static fd_set       master_read_fds;
-static fd_set       master_write_fds;
-static fd_set       work_read_fds;
-static fd_set       work_write_fds;
+static fd_set       master_read_fd_set;
+static fd_set       master_write_fd_set;
+static fd_set       work_read_fd_set;
+static fd_set       work_write_fd_set;
 
 #if (WIN32)
 static int          max_read;
@@ -23,8 +24,6 @@ static ngx_event_t  event_queue;
 static ngx_event_t  timer_queue;
 
 
-static void ngx_add_timer_core(ngx_event_t *ev, u_int timer);
-
 static fd_set *ngx_select_get_fd_set(ngx_socket_t fd, int event,
                                      ngx_log_t *log);
 
@@ -42,8 +41,8 @@ void ngx_select_init(int max_connections
         exit(1);
     }
 
-    FD_ZERO(&master_read_fds);
-    FD_ZERO(&master_write_fds);
+    FD_ZERO(&master_read_fd_set);
+    FD_ZERO(&master_write_fd_set);
 
     event_queue.prev = &event_queue;
     event_queue.next = &event_queue;
@@ -53,6 +52,7 @@ void ngx_select_init(int max_connections
 
     ngx_event_actions.add = ngx_select_add_event;
     ngx_event_actions.del = ngx_select_del_event;
+    ngx_event_actions.timer = ngx_select_add_timer;
     ngx_event_actions.process = ngx_select_process_events;
 
 #if (WIN32)
@@ -64,58 +64,76 @@ void ngx_select_init(int max_connections
 
 int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags)
 {
-    fd_set *fds;
-    ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+    ngx_connection_t *c;
+
+    c = (ngx_connection_t *) ev->data;
+
+    ngx_log_debug(ev->log, "select fd:%d event:%d" _ c->fd _ event);
 
-    if (event == NGX_TIMER_EVENT) {
-        ngx_add_timer_core(ev, flags);
-        return 0;
+#if (WIN32)
+    if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE)
+        || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE))
+    {
+        ngx_log_error(NGX_LOG_ERR, ev->log, 0,
+                      "maximum number of descriptors "
+                      "supported by select() is %d", FD_SETSIZE);
+        return NGX_ERROR;
     }
 
-    ngx_assert((flags != NGX_ONESHOT_EVENT), return -1, ev->log,
-               "ngx_select_add_event: NGX_ONESHOT_EVENT is not supported");
+    if (event == NGX_READ_EVENT) {
+        FD_SET(c->fd, &master_read_fd_set);
+        max_read++;
 
-    fds = ngx_select_get_fd_set(cn->fd, event, ev->log);
-    if (fds == NULL)
-        return -1;
+    } else if (event == NGX_WRITE_EVENT) {
+        FD_SET(c->fd, &master_write_fd_set);
+        max_write++;
+    }
+#else
+    if (event == NGX_READ_EVENT)
+        FD_SET(c->fd, &master_read_fd_set);
+
+    else if (event == NGX_WRITE_EVENT)
+        FD_SET(c->fd, &master_write_fd_set);
+
+    if (max_fd != -1 && max_fd < c->fd)
+        max_fd = c->fd;
+
+#endif
+
+    ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1: 0;
 
     ev->prev = &event_queue;
     ev->next = event_queue.next;
     event_queue.next->prev = ev;
     event_queue.next = ev;
 
-    FD_SET(cn->fd, fds);
-
-#if (WIN32)
-    switch (event) {
-    case NGX_READ_EVENT:
-        max_read++;
-        break;
-    case NGX_WRITE_EVENT:
-        max_write++;
-        break;
-    }
-#else
-    if (max_fd != -1 && max_fd < cn->fd)
-        max_fd = cn->fd;
-#endif
-
-    return 0;
+    return NGX_OK;
 }
 
 int ngx_select_del_event(ngx_event_t *ev, int event)
 {
-    fd_set *fds;
-    ngx_connection_t *cn = (ngx_connection_t *) ev->data;
+    ngx_connection_t *c;
+    c = (ngx_connection_t *) ev->data;
+
+#if (WIN32)
+    if (event == NGX_READ_EVENT) {
+        FD_CLR(c->fd, &master_read_fd_set);
+        max_read--;
 
-    if (event == NGX_TIMER_EVENT) {
-        ngx_del_timer(ev);
-        return 0;
+    } else if (event == NGX_WRITE_EVENT) {
+        FD_CLR(c->fd, &master_write_fd_set);
+        max_write--;
     }
+#else
+    if (event == NGX_READ_EVENT)
+        FD_CLR(c->fd, &master_read_fd_set);
 
-    fds = ngx_select_get_fd_set(cn->fd, event, ev->log);
-    if (fds == NULL)
-        return -1;
+    else if (event == NGX_WRITE_EVENT)
+        FD_CLR(c->fd, &master_write_fd_set);
+
+    if (max_fd == c->fd)
+        max_fd = -1;
+#endif
 
     if (ev->prev)
         ev->prev->next = ev->next;
@@ -128,70 +146,7 @@ int ngx_select_del_event(ngx_event_t *ev
     if (ev->prev)
         ev->next = NULL;
 
-    FD_CLR(cn->fd, fds);
-
-#if (WIN32)
-    switch (event) {
-    case NGX_READ_EVENT:
-        max_read--;
-        break;
-    case NGX_WRITE_EVENT:
-        max_write--;
-        break;
-    }
-#else
-    if (max_fd == cn->fd)
-        max_fd = -1;
-#endif
-
-    return 0;
-}
-
-static fd_set *ngx_select_get_fd_set(ngx_socket_t fd, int event, ngx_log_t *log)
-{
-    ngx_log_debug(log, "ngx_select_get_fd_set: %d %d" _ fd _ event);
-
-#if !(WIN32)
-    if (fd >= FD_SETSIZE) {
-        ngx_log_error(NGX_LOG_ERR, log, 0,
-                      "ngx_select_get_event: maximum descriptor number"
-                      "supported by select() is %d",
-                      FD_SETSIZE - 1);
-        return NULL;
-    }
-#endif
-
-    switch (event) {
-    case NGX_READ_EVENT:
-#if (WIN32)
-        if (max_read >= FD_SETSIZE) {
-            ngx_log_error(NGX_LOG_ERR, log, 0,
-                          "ngx_select_get_event: maximum number of descriptors "
-                          "supported by select() is %d",
-                          FD_SETSIZE);
-            return NULL;
-        }
-#endif
-        return &master_read_fds;
-
-    case NGX_WRITE_EVENT:
-#if (WIN32)
-        if (max_write >= FD_SETSIZE) {
-            ngx_log_error(NGX_LOG_ERR, log, 0,
-                          "ngx_select_get_event: maximum number of descriptors "
-                          "supported by select() is %d",
-                          FD_SETSIZE);
-            return NULL;
-        }
-#endif
-        return &master_write_fds;
-
-    default:
-        ngx_assert(0, return NULL, log,
-                      "ngx_select_get_fd_set: invalid event %d" _ event);
-    }
-
-    return NULL;
+    return NGX_OK;
 }
 
 int ngx_select_process_events(ngx_log_t *log)
@@ -199,11 +154,11 @@ int ngx_select_process_events(ngx_log_t 
     int                ready, found;
     u_int              timer, delta;
     ngx_event_t       *ev, *nx;
-    ngx_connection_t  *cn;
+    ngx_connection_t  *c;
     struct timeval     tv, *tp;
 
-    work_read_fds = master_read_fds;
-    work_write_fds = master_write_fds;
+    work_read_fd_set = master_read_fd_set;
+    work_write_fd_set = master_write_fd_set;
 
     if (timer_queue.timer_next != &timer_queue) {
         timer = timer_queue.timer_next->timer_delta;
@@ -222,27 +177,27 @@ int ngx_select_process_events(ngx_log_t 
 #if !(WIN32)
     if (max_fd == -1) {
         for (ev = event_queue.next; ev != &event_queue; ev = ev->next) {
-            cn = (ngx_connection_t *) ev->data;
-            if (max_fd < cn->fd)
-                max_fd = cn->fd;
+            c = (ngx_connection_t *) ev->data;
+            if (max_fd < c->fd)
+                max_fd = c->fd;
         }
 
-        ngx_log_debug(log, "ngx_select_process_events: change max_fd: %d" _
-                      max_fd);
+        ngx_log_debug(log, "change max_fd: %d" _ max_fd);
     }
 #endif
 
     ngx_log_debug(log, "ngx_select_process_events: timer: %d" _ timer);
 
 #if (WIN32)
-    if ((ready = select(0, &work_read_fds, &work_write_fds, NULL, tp))
+    if ((ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp))
 #else
-    if ((ready = select(max_fd + 1, &work_read_fds, &work_write_fds, NULL, tp))
+    if ((ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set,
+                        NULL, tp))
 #endif
                == -1) {
         ngx_log_error(NGX_LOG_ALERT, log, ngx_socket_errno,
                      "ngx_select_process_events: select failed");
-        return -1;
+        return NGX_ERROR;
     }
 
     ngx_log_debug(log, "ngx_select_process_events: ready %d" _ ready);
@@ -251,7 +206,7 @@ int ngx_select_process_events(ngx_log_t 
         delta = ngx_msec() - delta;
 
     } else {
-        ngx_assert((ready != 0), return -1, log,
+        ngx_assert((ready != 0), return NGX_ERROR, log,
                    "ngx_select_process_events: "
                    "select returns no events without timeout");
     }
@@ -268,14 +223,9 @@ int ngx_select_process_events(ngx_log_t 
                 delta -= ev->timer_delta;
                 nx = ev->timer_next;
                 ngx_del_timer(ev);
-#if 1
                 ev->timedout = 1;
                 if (ev->event_handler(ev) == -1)
                     ev->close_handler(ev);
-#else
-                if (ev->timer_handler(ev) == -1)
-                    ev->close_handler(ev);
-#endif
                 ev = nx;
             }
 
@@ -285,26 +235,35 @@ int ngx_select_process_events(ngx_log_t 
     }
 
     for (ev = event_queue.next; ev != &event_queue; ev = ev->next) {
-        cn = (ngx_connection_t *) ev->data;
+        c = (ngx_connection_t *) ev->data;
         found = 0;
 
         if (ev->write) {
-            if (FD_ISSET(cn->fd, &work_write_fds)) {
+            if (FD_ISSET(c->fd, &work_write_fd_set)) {
                 ngx_log_debug(log, "ngx_select_process_events: write %d" _
-                              cn->fd);
+                              c->fd);
                 found = 1;
             }
 
         } else {
-            if (FD_ISSET(cn->fd, &work_read_fds)) {
+            if (FD_ISSET(c->fd, &work_read_fd_set)) {
                 ngx_log_debug(log, "ngx_select_process_events: read %d" _
-                              cn->fd);
+                              c->fd);
                 found = 1;
             }
         }
 
         if (found) {
             ev->ready = 1;
+
+            if (ev->oneshot) {
+                ngx_del_timer(ev);
+                if (ev->write)
+                    ngx_select_del_event(ev, NGX_WRITE_EVENT);
+                else
+                    ngx_select_del_event(ev, NGX_READ_EVENT);
+            }
+
             if (ev->event_handler(ev) == -1)
                 ev->close_handler(ev);
 
@@ -313,13 +272,13 @@ int ngx_select_process_events(ngx_log_t 
 
     }
 
-    ngx_assert((ready == 0), return 0, log,
+    ngx_assert((ready == 0), /* void */ ; , log,
                "ngx_select_process_events: ready != events");
 
-    return 0;
+    return NGX_OK;
 }
 
-static void ngx_add_timer_core(ngx_event_t *ev, u_int timer)
+void ngx_select_add_timer(ngx_event_t *ev, ngx_msec_t timer)
 {
     ngx_event_t *e;
 
@@ -336,19 +295,3 @@ static void ngx_add_timer_core(ngx_event
     e->timer_prev->timer_next = ev;
     e->timer_prev = ev;
 }
-
-#if 0
-static void ngx_inline ngx_del_timer(ngx_event_t *ev)
-{
-    if (ev->timer_prev)
-        ev->timer_prev->timer_next = ev->timer_next;
-
-    if (ev->timer_next) {
-        ev->timer_next->timer_prev = ev->timer_prev;
-        ev->timer_next = NULL;
-    }
-
-    if (ev->timer_prev)
-        ev->timer_prev = NULL;
-}
-#endif
--- a/src/event/modules/ngx_select_module.h
+++ b/src/event/modules/ngx_select_module.h
@@ -10,6 +10,7 @@ void ngx_select_init(int max_connections
 int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags);
 int ngx_select_del_event(ngx_event_t *ev, int event);
 int ngx_select_set_event(ngx_event_t *ev, int filter, u_int flags);
+void ngx_select_add_timer(ngx_event_t *ev, ngx_msec_t timer);
 int ngx_select_process_events(ngx_log_t *log);
 
 
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_string.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
 #include <ngx_listen.h>
@@ -19,7 +20,7 @@ ngx_event_t         *ngx_read_events, *n
 
 #if !(USE_KQUEUE)
 
-#if 0
+#if 1
 ngx_event_type_e     ngx_event_type = NGX_SELECT_EVENT;
 #else
 ngx_event_type_e     ngx_event_type = NGX_KQUEUE_EVENT;
@@ -78,7 +79,10 @@ void ngx_pre_thread(ngx_array_t *ls, ngx
         ngx_connections[fd].handler = s[i].handler;
         ngx_connections[fd].log = s[i].log;
 
-        ngx_read_events[fd].log = ngx_connections[fd].log;
+        ngx_test_null(ngx_read_events[fd].log,
+                      ngx_palloc(pool, sizeof(ngx_log_t)), /* void */ ; );
+        ngx_memcpy(ngx_read_events[fd].log, ngx_connections[fd].log,
+                   sizeof(ngx_log_t));
         ngx_read_events[fd].data = &ngx_connections[fd];
         ngx_read_events[fd].event_handler = &ngx_event_accept;
         ngx_read_events[fd].listening = 1;
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -4,6 +4,7 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_time.h>
 #include <ngx_socket.h>
 #include <ngx_log.h>
 #include <ngx_alloc.h>
@@ -40,11 +41,16 @@ struct ngx_event_s {
                                 /*   accept: 1 if accept many, 0 otherwise   */
 
     /* flags - int are probably faster on write then bits ??? */
+#if !(USE_KQUEUE)
+    unsigned         oneshot:1;
+#endif
     unsigned         listening:1;
     unsigned         write:1;
 
     unsigned         ready:1;
     unsigned         timedout:1;
+    unsigned         blocked:1;
+
     unsigned         process:1;
     unsigned         read_discarded:1;
 
@@ -72,6 +78,7 @@ typedef enum {
 typedef struct {
     int  (*add)(ngx_event_t *ev, int event, u_int flags);
     int  (*del)(ngx_event_t *ev, int event);
+    void (*timer)(ngx_event_t *ev, ngx_msec_t timer);
     int  (*process)(ngx_log_t *log);
     int  (*read)(ngx_event_t *ev, char *buf, size_t size);
 /*
@@ -93,21 +100,22 @@ NGX_AIO_EVENT              overlapped, a
 
 #define NGX_READ_EVENT     EVFILT_READ
 #define NGX_WRITE_EVENT    EVFILT_WRITE
-#define NGX_TIMER_EVENT    (-EVFILT_SYSCOUNT - 1)
 
 #define NGX_LEVEL_EVENT    0
 #define NGX_ONESHOT_EVENT  EV_ONESHOT
+
+#ifndef HAVE_CLEAR_EVENT
+#define HAVE_CLEAR_EVENT   1
 #define NGX_CLEAR_EVENT    EV_CLEAR
+#endif
 
 #else
 
 #define NGX_READ_EVENT     0
 #define NGX_WRITE_EVENT    1
-#define NGX_TIMER_EVENT    2
 
 #define NGX_LEVEL_EVENT    0
 #define NGX_ONESHOT_EVENT  1
-#define NGX_CLEAR_EVENT    2
 
 #endif
 
@@ -116,8 +124,11 @@ NGX_AIO_EVENT              overlapped, a
 
 #define ngx_init_events      ngx_kqueue_init
 #define ngx_process_events   ngx_kqueue_process_events
-#define ngx_add_event        ngx_kqueue_add_event
-#define ngx_del_event        ngx_kqueue_del_event
+#define ngx_kqueue_add_event(ev, event)                                       \
+            ngx_kqueue_set_event(ev, event, EV_ADD | flags)
+#define ngx_kqueue_del_event(ev, event)                                       \
+            ngx_kqueue_set_event(ev, event, EV_DELETE)
+#define ngx_add_timer        ngx_kqueue_add_timer
 #define ngx_event_recv       ngx_event_recv_core
 
 #else
@@ -126,13 +137,12 @@ NGX_AIO_EVENT              overlapped, a
 #define ngx_process_events   ngx_event_actions.process
 #define ngx_add_event        ngx_event_actions.add
 #define ngx_del_event        ngx_event_actions.del
+#define ngx_add_timer        ngx_event_actions.timer
 #define ngx_event_recv       ngx_event_recv_core
 
 #endif
 
 
-#define ngx_add_timer(ev, time)  ngx_add_event(ev, NGX_TIMER_EVENT, time)
-
 static void ngx_inline ngx_del_timer(ngx_event_t *ev)
 {
     if (ev->timer_prev)
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -63,7 +63,8 @@ int ngx_event_accept(ngx_event_t *ev)
         ngx_connections[s].write = &ngx_write_events[s];
 
         ngx_connections[s].fd = s;
-        ngx_read_events[s].unexpected_eof = 1;
+        ngx_connections[s].unexpected_eof = 1;
+        ngx_write_events[s].write = 1;
         ngx_write_events[s].ready = 1;
 
         ngx_write_events[s].timer = ngx_read_events[s].timer = 10000;
--- a/src/event/ngx_event_write.c
+++ b/src/event/ngx_event_write.c
@@ -1,5 +1,6 @@
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_types.h>
 #include <ngx_alloc.h>
 #include <ngx_array.h>
@@ -10,7 +11,7 @@
 #include <ngx_event_write.h>
 
 
-ngx_chain_t *ngx_event_write(ngx_connection_t *cn, ngx_chain_t *in,
+ngx_chain_t *ngx_event_write(ngx_connection_t *c, ngx_chain_t *in,
                              off_t flush)
 {
     int           rc;
@@ -24,10 +25,10 @@ ngx_chain_t *ngx_event_write(ngx_connect
     ch = in;
     file = NULL;
 
-    ngx_test_null(header, ngx_create_array(cn->pool, 10, sizeof(ngx_iovec_t)),
+    ngx_test_null(header, ngx_create_array(c->pool, 10, sizeof(ngx_iovec_t)),
                   (ngx_chain_t *) -1);
 
-    ngx_test_null(trailer, ngx_create_array(cn->pool, 10, sizeof(ngx_iovec_t)),
+    ngx_test_null(trailer, ngx_create_array(c->pool, 10, sizeof(ngx_iovec_t)),
                   (ngx_chain_t *) -1);
 
     do {
@@ -62,7 +63,7 @@ ngx_chain_t *ngx_event_write(ngx_connect
 
 #if (HAVE_MAX_SENDFILE_IOVEC)
         if (file && header->nelts > HAVE_MAX_SENDFILE_IOVEC) {
-            rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts, header->nelts,
+            rc = ngx_sendv(c->fd, (ngx_iovec_t *) header->elts, header->nelts,
                            &sent);
         } else {
 #endif
@@ -90,44 +91,57 @@ ngx_chain_t *ngx_event_write(ngx_connect
             }
 
             if (file) {
-                rc = ngx_sendfile(cn->fd,
+                rc = ngx_sendfile(c->fd,
                                   (ngx_iovec_t *) header->elts, header->nelts,
-                                  file->fd, file->pos.file,
+                                  file->file->fd, file->pos.file,
                                   (size_t) (file->last.file - file->pos.file),
                                   (ngx_iovec_t *) trailer->elts, trailer->nelts,
-                                  &sent, cn->log);
+                                  &sent, c->log);
             } else {
-                rc = ngx_sendv(cn->fd, (ngx_iovec_t *) header->elts,
-                               header->nelts, (size_t *) &sent);
-                ngx_log_debug(cn->log, "sendv: %d" _ sent);
+                size_t sendv_sent;
+
+                sendv_sent = 0;
+                rc = ngx_sendv(c->fd, (ngx_iovec_t *) header->elts,
+                               header->nelts, &sendv_sent);
+                sent = sendv_sent;
+                ngx_log_debug(c->log, "sendv: " QD_FMT _ sent);
             }
 #if (HAVE_MAX_SENDFILE_IOVEC)
         }
 #endif
         /* save sent for logging */
 
-        if (rc == -1)
+        if (rc == NGX_ERROR)
             return (ngx_chain_t *) -1;
 
+        c->sent = sent;
         flush -= sent;
 
         for (ch = in; ch; ch = ch->next) {
+
+            ngx_log_debug(c->log, "ch event write: %x %qx %qd" _
+                          ch->hunk->type _
+                          ch->hunk->pos.file _
+                          ch->hunk->last.file - ch->hunk->pos.file);
+
             if (sent >= ch->hunk->last.file - ch->hunk->pos.file) {
                 sent -= ch->hunk->last.file - ch->hunk->pos.file;
-                ch->hunk->last.file = ch->hunk->pos.file;
+                ch->hunk->pos.file = ch->hunk->last.file;
 
-                ngx_log_debug(cn->log, "event write: %qx 0" _
-                              ch->hunk->pos.file);
+                ngx_log_debug(c->log, "event write: " QX_FMT " 0 " QD_FMT _
+                              ch->hunk->pos.file _ sent);
 
+/*
                 if (ch->hunk->type & NGX_HUNK_LAST)
                    break;
+*/
 
                 continue;
             }
 
             ch->hunk->pos.file += sent;
 
-            ngx_log_debug(cn->log, "event write: %qx %qd" _
+            ngx_log_debug(c->log, "event write: %qx %qd" _
                           ch->hunk->pos.file _
                           ch->hunk->last.file - ch->hunk->pos.file);
 
@@ -135,7 +149,7 @@ ngx_chain_t *ngx_event_write(ngx_connect
         }
 
     /* flush hunks if threaded state */
-    } while (cn->write->context && flush > 0);
+    } while (c->write->context && flush > 0);
 
     ngx_destroy_array(trailer);
     ngx_destroy_array(header);
--- 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 @@ int ngx_http_header_filter(ngx_http_requ
     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;
 
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -26,7 +26,7 @@ int ngx_http_static_handler(ngx_http_req
 {
     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 @@ int ngx_http_static_handler(ngx_http_req
 
 */
 
+    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 @@ int ngx_http_static_handler(ngx_http_req
         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 @@ int ngx_http_static_handler(ngx_http_req
     }
 
     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 @@ int ngx_http_static_handler(ngx_http_req
     /* 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);
-*/
+    ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)),
+                  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);
+    h->last.file = ngx_file_size(r->fileinfo);
 
     /* 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->file, ngx_pcalloc(r->pool, sizeof(ngx_file_t)),
                   NGX_HTTP_INTERNAL_SERVER_ERROR);
-*/
-    ch->hunk = h;
-    ch->next = NULL;
+    h->file->fd = r->fd;
+    h->file->log = r->connection->log;
 
-    /* STUB */
-    rc = ngx_http_write_filter(r, ch);
-    ngx_log_debug(r->connection->log, "write_filter: %d" _ rc);
+    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
--- 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 @@ int ngx_http_init(ngx_pool_t *pool, ngx_
 {
     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 @@ int ngx_http_init(ngx_pool_t *pool, ngx_
 #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 @@ int ngx_http_init(ngx_pool_t *pool, ngx_
     ls->server = &ngx_http_server;
     ls->log = log;
 
+
     return 1;
 }
 
--- 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 {
 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 @@ struct ngx_http_request_s {
     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 @@ struct ngx_http_request_s {
 
     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 @@ typedef struct {
 #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);
 
 
--- 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(ngx_
 
 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 @@ int ngx_http_init_connection(ngx_connect
 
     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 @@ int ngx_http_init_request(ngx_event_t *e
     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 @@ int ngx_http_process_request(ngx_event_t
     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 @@ int ngx_http_process_request(ngx_event_t
 
         /* 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 @@ static int ngx_http_process_request_line
         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;
     }
 
+    ctx = r->connection->log->data;
     r->connection->log->handler = NULL;
-    ctx = r->connection->log->data;
-
     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 @@ static int ngx_http_process_request_head
         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) {
+            ctx = r->connection->log->data;
             r->connection->log->handler = NULL;
-            ctx = r->connection->log->data;
             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;
+}
+
+static int ngx_http_read_discarded_body(ngx_event_t *ev)
+{
+    size_t   size;
+    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 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;
 }
 
-#if 0
-static int ngx_http_lock_read(ngx_event_t *ev)
+static int ngx_http_handler(ngx_http_request_t *r)
 {
-    ngx_del_event(ev, NGX_READ_EVENT);
-    ev->read_blocked = 1;
+    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
+*/
 }
-#endif
 
-static int ngx_http_process_http_request(ngx_http_request_t *r)
+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 @@ static int ngx_http_process_http_request
 
     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 @@ static int ngx_http_process_http_request
 
     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_output_filter(r, NULL);
+
+    ngx_log_debug(ev->log, "output_filter: %d" _ rc);
+
+    if (rc == NGX_AGAIN) {
 
-    rc = ngx_http_filter(r, NULL);
+        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 (rc == NGX_AGAIN)
+        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 @@ static int ngx_http_writer(ngx_event_t *
     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 @@ static int ngx_http_keepalive_handler(ng
 #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 @@ static int ngx_http_close_request(ngx_ht
 
     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 int ngx_http_close_request(ngx_ht
 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);
rename from src/http/ngx_http_filter.c
rename to src/http/ngx_http_output_filter.c
--- a/src/http/ngx_http_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -1,65 +1,74 @@
 
 
+#include <ngx_core.h>
+#include <ngx_files.h>
+#include <ngx_string.h>
 #include <ngx_hunk.h>
 #include <ngx_http.h>
-#include <ngx_http_filter.h>
-
-
-ngx_http_module_t  ngx_http_filter_module;
+#include <ngx_http_output_filter.h>
 
 
 /* STUB */
-static ngx_http_filter_ctx_t module_ctx;
+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);
 
-void ngx_http_filter_init()
+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_filter_module.ctx = &module_ctx;
+     ngx_http_output_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 ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk)
 {
-    int      rc;
+    int      rc, first;
     size_t   size;
     ssize_t  n;
     ngx_chain_t  *ce;
-    ngx_http_filter_ctx_t  *ctx;
+    ngx_http_output_filter_ctx_t  *ctx;
 
-    ctx = (ngx_http_filter_ctx_t *)
+    ctx = (ngx_http_output_filter_ctx_t *)
                               ngx_get_module_ctx(r->main ? r->main : r,
-                                                      &ngx_http_filter_module);
+                                               &ngx_http_output_filter_module);
 
     if (hunk && (hunk->type & NGX_HUNK_LAST))
         ctx->last = 1;
 
-    /* input chain is not empty */
-    if (ctx->in) {
+    first = 1;
 
-        while (ctx->in) {
+    while (first || ctx->in) {
+
+         /* input chain is not empty */
+        if (ctx->in) {
 
             /* add hunk to input chain */
-            if (hunk) {
+            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);
+                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);
@@ -68,7 +77,7 @@ int ngx_http_filter(ngx_http_request_t *
             } else {
                 ctx->out.hunk = ctx->hunk;
 
-                rc = ngx_http_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
+                rc = ngx_http_output_filter_copy_hunk(ctx->hunk, ctx->in->hunk);
 #if (NGX_FILE_AIO)
                 if (rc == NGX_AGAIN)
                     return rc;
@@ -82,10 +91,10 @@ int ngx_http_filter(ngx_http_request_t *
                     ctx->out.next = ctx->in->next;
 
                     for (ce = ctx->in->next; ce; ce = ce->next) {
-                        if (ce->type & NGX_HUNK_FILE)
+                        if (ce->hunk->type & NGX_HUNK_FILE)
                             break;
 
-                        if ((ce->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP)
+                        if ((ce->hunk->type & NGX_HUNK_MEMORY|NGX_HUNK_MMAP)
                             && (r->filter & NGX_HTTP_FILTER_NEED_TEMP))
                             break;
                     }
@@ -99,90 +108,99 @@ int ngx_http_filter(ngx_http_request_t *
                 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 {
-
-        if (hunk == NULL) {
-            rc = ctx->next_filter(r, NULL);
-
+        /* input chain is empty */
         } 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))
-               ) {
+            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;
 
-                /* 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,
+                            } 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 = ctx->next_filter(r, NULL);
+                            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 {
-                    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);
+                    ctx->out.hunk = hunk;
+                    ctx->out.next = NULL;
 
-                            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);
-                    }
+                    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) {
-        /* STUB */
-        return NGX_ERROR;
-    }
+    if (rc == NGX_OK && ctx->last)
+        return NGX_OK;
 
     if (rc == NGX_OK) {
         ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start;
@@ -195,20 +213,19 @@ int ngx_http_filter(ngx_http_request_t *
 }
 
 
-int ngx_http_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src, ngx_log_t *log)
+static int ngx_http_output_filter_copy_hunk(ngx_hunk_t *dst, ngx_hunk_t *src)
 {
-    size_t  size;
+    size_t   size;
+    ssize_t  n;
 
-    size = hunk->last.mem - hunk->pos.mem;
+    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->handle, dst->pos.mem, size);
+        n = ngx_read_file(src->file, dst->pos.mem, size, src->pos.file);
 
         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)
@@ -217,8 +234,8 @@ int ngx_http_filter_copy_hunk(ngx_hunk_t
 #endif
 
         } else {
-            ngx_assert((n == size), /* void */ ; , log,
-                       ngx_read_file_n " reads only %d of %d for client" _
+            ngx_assert((n == size), /* void */ ; , src->file->log,
+                       ngx_read_file_n " reads only %d of %d" _
                        n _ size);
         }
 
rename from src/http/ngx_http_filter.h
rename to src/http/ngx_http_output_filter.h
--- 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 @@ typedef struct {
     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_ */
--- 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_event_write.h>
 #include <ngx_http.h>
-#include <ngx_http_filter.h>
-#include <ngx_event_write.h>
+#include <ngx_http_output_filter.h>
 
 #include <ngx_http_write_filter.h>
 
@@ -48,7 +48,7 @@ int ngx_http_write_filter(ngx_http_reque
                       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 @@ int ngx_http_write_filter(ngx_http_reque
                       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 @@ int ngx_http_write_filter(ngx_http_reque
 
     ctx->out = chain;
 
+    ngx_log_debug(r->connection->log, "write filter %x" _ chain);
+
     return (chain ? NGX_AGAIN : NGX_OK);
 }
--- a/src/http/ngx_http_write_filter.h
+++ b/src/http/ngx_http_write_filter.h
@@ -7,5 +7,7 @@ typedef struct {
     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_ */
--- a/src/os/unix/freebsd/ngx_sendfile.c
+++ b/src/os/unix/freebsd/ngx_sendfile.c
@@ -1,5 +1,6 @@
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_types.h>
 #include <ngx_file.h>
 #include <ngx_socket.h>
@@ -14,12 +15,6 @@
        check sent if errno == EINTR then should return right sent.
 */
 
-/*
-  returns
-      0 done
-     -1 error
-*/
-
 #if (HAVE_FREEBSD_SENDFILE)
 
 int ngx_sendfile(ngx_socket_t s,
@@ -50,7 +45,7 @@ int ngx_sendfile(ngx_socket_t s,
         if (err != NGX_EAGAIN && err != NGX_EINTR) {
             ngx_log_error(NGX_LOG_ERR, log, err,
                          "ngx_sendfile: sendfile failed");
-            return -1;
+            return NGX_ERROR;
 
         } else {
             ngx_log_error(NGX_LOG_INFO, log, err,
@@ -61,7 +56,7 @@ int ngx_sendfile(ngx_socket_t s,
     ngx_log_debug(log, "ngx_sendfile: %d, @%qd %qd:%d" _
                   rc _ offset _ *sent _ nbytes);
 
-    return 0;
+    return NGX_OK;
 }
 
 #endif
rename from src/os/unix/ngx_file.c
rename to src/os/unix/ngx_files.c
--- a/src/os/unix/ngx_file.c
+++ b/src/os/unix/ngx_files.c
@@ -1,8 +1,19 @@
 
+#include <ngx_core.h>
+#include <ngx_file.h>
+
+ssize_t ngx_read_file(ngx_file_t *file, char *buf, size_t size, off_t offset)
+{
+    ssize_t n;
 
-ssize_t ngx_read_file(ngx_file_t file, char *buf, size_t size, off_t offset)
-{
-    return pread(file->fd, buf, size, offset);
+    ngx_log_debug(file->log, "read: %x, %d, %qd" _ buf _ size _ offset);
+
+    n = pread(file->fd, buf, size, offset);
+
+    if (n == NGX_ERROR)
+        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "read() failed");
+
+    return n;
 }
 
 #if 0
rename from src/os/unix/ngx_file.h
rename to src/os/unix/ngx_files.h
--- a/src/os/unix/ngx_file.h
+++ b/src/os/unix/ngx_files.h
@@ -1,5 +1,5 @@
-#ifndef _NGX_FILE_H_INCLUDED_
-#define _NGX_FILE_H_INCLUDED_
+#ifndef _NGX_FILES_H_INCLUDED_
+#define _NGX_FILES_H_INCLUDED_
 
 
 #include <sys/types.h>
@@ -12,7 +12,6 @@ typedef struct stat              ngx_fil
 #define ngx_open_file            open
 #define ngx_open_file_n          "open()"
 
-#define ngx_read_file            read
 #define ngx_read_file_n          "read()"
 
 #define NGX_FILE_RDONLY          O_RDONLY
@@ -29,4 +28,4 @@ typedef struct stat              ngx_fil
 #define ngx_file_mtime(sb)       sb.st_mtime
 
 
-#endif /* _NGX_FILE_H_INCLUDED_ */
+#endif /* _NGX_FILES_H_INCLUDED_ */
--- a/src/os/unix/ngx_sendfile.h
+++ b/src/os/unix/ngx_sendfile.h
@@ -3,7 +3,7 @@
 
 
 #include <ngx_types.h>
-#include <ngx_file.h>
+#include <ngx_files.h>
 #include <ngx_socket.h>
 #include <ngx_log.h>
 #include <ngx_sendv.h>
--- a/src/os/unix/ngx_sendv.c
+++ b/src/os/unix/ngx_sendv.c
@@ -1,15 +1,18 @@
 
+#include <ngx_core.h>
 #include <ngx_types.h>
 #include <ngx_socket.h>
 #include <ngx_sendv.h>
 
 ssize_t ngx_sendv(ngx_socket_t s, ngx_iovec_t *iovec, int n, size_t *sent)
 {
-     ssize_t rc = writev(s, iovec, n);
+     ssize_t rc;
+
+     rc = writev(s, iovec, n);
 
      if (rc == -1)
-         return -1;
+         return NGX_ERROR;
 
      *sent = rc;
-     return 0;
+     return NGX_OK;
 }
--- a/src/os/unix/ngx_time.h
+++ b/src/os/unix/ngx_time.h
@@ -4,6 +4,8 @@
 
 #include <ngx_config.h>
 
+typedef u_int          ngx_msec_t;
+
 typedef struct tm      ngx_tm_t;
 
 #define ngx_tm_sec     tm_sec
@@ -18,7 +20,7 @@ typedef struct tm      ngx_tm_t;
 
 void ngx_localtime(ngx_tm_t *tm);
 
-u_int ngx_msec(void);
+ngx_msec_t ngx_msec(void);
 
 
 #endif /* _NGX_TIME_H_INCLUDED_ */
--- a/src/os/win32/ngx_errno.h
+++ b/src/os/win32/ngx_errno.h
@@ -6,12 +6,14 @@
 
 typedef DWORD             ngx_err_t;
 
-#define ngx_errno         GetLastError()
-#define ngx_socket_errno  WSAGetLastError()
+#define ngx_errno                  GetLastError()
+#define ngx_socket_errno           WSAGetLastError()
+#define ngx_set_socket_errno(err)  WSASetLastError(err)
 
 #define NGX_ENOENT        ERROR_FILE_NOT_FOUND
 #define NGX_EAGAIN        WSAEWOULDBLOCK
 #define NGX_EADDRINUSE    WSAEADDRINUSE
+#define NGX_ETIMEDOUT     WSAETIMEDOUT
 
 int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size);
 
new file mode 100644
--- /dev/null
+++ b/src/os/win32/ngx_files.c
@@ -0,0 +1,18 @@
+
+#include <ngx_core.h>
+#include <ngx_types.h>
+#include <ngx_file.h>
+
+ssize_t ngx_read_file(ngx_file_t *file, char *buf, size_t size, off_t offset)
+{
+    size_t n;
+
+    if (ReadFile(file->fd, buf, size, &n, NULL) == 0) {
+        ngx_log_error(NGX_LOG_ERR, file->log, ngx_errno, "ReadFile() failed");
+        return NGX_ERROR;
+    }
+
+    return n;
+}
+
+
rename from src/os/win32/ngx_file.h
rename to src/os/win32/ngx_files.h
--- a/src/os/win32/ngx_file.h
+++ b/src/os/win32/ngx_files.h
@@ -1,5 +1,5 @@
-#ifndef _NGX_FILE_H_INCLUDED_
-#define _NGX_FILE_H_INCLUDED_
+#ifndef _NGX_FILES_H_INCLUDED_
+#define _NGX_FILES_H_INCLUDED_
 
 
 #include <ngx_config.h>
@@ -21,9 +21,9 @@ typedef BY_HANDLE_FILE_INFORMATION  ngx_
                        FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,  \
                        NULL, OPEN_EXISTING, 0, NULL)
 
-#define ngx_open_file_n             "CreateFile"
+#define ngx_open_file_n             "CreateFile()"
 
-#define NGX_FILE_RDONLY          GENERIC_READ
+#define NGX_FILE_RDONLY             GENERIC_READ
 
 
 int ngx_file_type(char *filename, ngx_file_info_t *fi);
@@ -51,4 +51,7 @@ 1970 - 1601:
 */
 
 
-#endif /* _NGX_FILE_H_INCLUDED_ */
+#define ngx_read_file_n             "ReadFile()"
+
+
+#endif /* _NGX_FILES_H_INCLUDED_ */
--- a/src/os/win32/ngx_sendfile.c
+++ b/src/os/win32/ngx_sendfile.c
@@ -1,6 +1,8 @@
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_types.h>
+#include <ngx_files.h>
 #include <ngx_socket.h>
 #include <ngx_errno.h>
 #include <ngx_log.h>
@@ -13,17 +15,11 @@
        TransmitPackets
 */
 
-/*
-  returns
-      0 done
-     -1 error
-*/
-
 #if (HAVE_WIN32_TRANSMITFILE)
 
 int ngx_sendfile(ngx_socket_t s,
                  ngx_iovec_t *headers, int hdr_cnt,
-                 ngx_file_t fd, off_t offset, size_t nbytes,
+                 ngx_fd_t fd, off_t offset, size_t nbytes,
                  ngx_iovec_t *trailers, int trl_cnt,
                  off_t *sent,
                  ngx_log_t *log)
@@ -65,15 +61,13 @@ int ngx_sendfile(ngx_socket_t s,
     /* set sent */
 #if 0
     rc = WSAGetOverlappedResult(s, &olp, (unsigned long *) sent, 0, NULL);
+#else
+    *sent = olp.InternalHigh;
+    rc = 1;
 #endif
 
-#if 0
     ngx_log_debug(log, "ngx_sendfile: %d, @%I64d %I64d:%d" _
                   tfrc _ offset _ *sent _ nbytes);
-#else
-    ngx_log_debug(log, "ngx_sendfile: %d, @%I64d %d:%d" _
-                  tfrc _ offset _ olp.InternalHigh _ nbytes);
-#endif
 
     if (rc == 0) {
         err = ngx_socket_errno;
@@ -85,7 +79,7 @@ int ngx_sendfile(ngx_socket_t s,
         if (tf_err != NGX_EAGAIN) {
             ngx_log_error(NGX_LOG_ERR, log, tf_err,
                           "ngx_sendfile: TransmitFile failed");
-            return -1;
+            return NGX_ERROR;
         }
 
         ngx_log_error(NGX_LOG_INFO, log, tf_err,
@@ -94,9 +88,9 @@ int ngx_sendfile(ngx_socket_t s,
     }
 
     if (rc == 0)
-        return -1;
+        return NGX_ERROR;
 
-    return 0;
+    return NGX_OK;
 }
 
 #endif
--- a/src/os/win32/ngx_sendfile.h
+++ b/src/os/win32/ngx_sendfile.h
@@ -4,13 +4,14 @@
 
 #include <ngx_config.h>
 #include <ngx_types.h>
+#include <ngx_files.h>
 #include <ngx_socket.h>
 #include <ngx_log.h>
 #include <ngx_sendv.h>
 
 int ngx_sendfile(ngx_socket_t s,
                  ngx_iovec_t *headers, int hdr_cnt,
-                 ngx_file_t fd, off_t offset, size_t nbytes,
+                 ngx_fd_t fd, off_t offset, size_t nbytes,
                  ngx_iovec_t *trailers, int trl_cnt,
                  off_t *sent,
                  ngx_log_t *log);
--- a/src/os/win32/ngx_socket.h
+++ b/src/os/win32/ngx_socket.h
@@ -5,7 +5,10 @@
 #include <ngx_config.h>
 #include <ngx_log.h>
 
+#define INET_ADDRSTRLEN     16
+
 typedef SOCKET  ngx_socket_t;
+typedef int     socklen_t;
 
 void ngx_init_sockets(ngx_log_t *log);
 
@@ -13,11 +16,12 @@ void ngx_init_sockets(ngx_log_t *log);
             WSASocket(af, type, proto, NULL, 0, flags)
 #define ngx_socket_n        "WSASocket()"
 
-int ngx_nonblocking_n(s);
+int ngx_nonblocking(ngx_socket_t s);
 #define ngx_nonblocking_n   "ioctlsocket(FIONBIO)"
 
 #define ngx_close_socket    closesocket
 #define ngx_close_socket_n  "closesocket()"
 
 
+
 #endif /* _NGX_SOCKET_H_INCLUDED_ */
--- a/src/os/win32/ngx_time.h
+++ b/src/os/win32/ngx_time.h
@@ -4,6 +4,8 @@
 
 #include <windows.h>
 
+typedef unsigned int   ngx_msec_t;
+
 typedef SYSTEMTIME     ngx_tm_t;
 typedef FILETIME       ngx_mtime_t;
 
--- a/src/os/win32/ngx_types.h
+++ b/src/os/win32/ngx_types.h
@@ -5,6 +5,7 @@
 #include <ngx_config.h>
 
 
+typedef int               ssize_t;
 typedef long              time_t;