changeset 24:77c7629a2627

nginx-0.0.1-2002-12-10-21:05:12 import
author Igor Sysoev <igor@sysoev.ru>
date Tue, 10 Dec 2002 18:05:12 +0000
parents f540a63026c9
children a8b156554dfe
files src/core/nginx.c src/core/ngx_connection.h src/core/ngx_listen.h src/event/ngx_event.c src/event/ngx_event_accept.c src/http/modules/ngx_http_event_proxy_handler.c src/http/modules/ngx_http_event_proxy_handler.h src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_index_handler.h src/http/modules/ngx_http_static_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_config.c src/http/ngx_http_core.c src/http/ngx_http_event.c src/http/ngx_http_get_time.c src/http/ngx_http_header_filter.c src/http/ngx_http_modules.c src/http/ngx_http_output_filter.c src/http/ngx_http_parse.c src/http/ngx_http_parse_time.c src/http/ngx_http_special_response.c src/http/ngx_http_write_filter.c src/os/unix/ngx_files.h
diffstat 24 files changed, 721 insertions(+), 381 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -18,6 +18,7 @@
 /* */
 
 
+static void ngx_set_signals(ngx_log_t *log);
 static void ngx_open_listening_sockets(ngx_log_t *log);
 
 
@@ -42,6 +43,8 @@ int main(int argc, char *const *argv)
     ngx_pool = ngx_create_pool(16 * 1024, &ngx_log);
     /* */
 
+    ngx_set_signals(&ngx_log);
+
     ngx_init_sockets(&ngx_log);
 
     /* TODO: read config */
@@ -70,6 +73,20 @@ int main(int argc, char *const *argv)
     return 0;
 }
 
+static void ngx_set_signals(ngx_log_t *log)
+{
+    struct sigaction sa;
+
+    ngx_memzero(&sa, sizeof(struct sigaction));
+    sa.sa_handler = SIG_IGN;
+    sigemptyset(&sa.sa_mask);
+    if (sigaction(SIGPIPE, &sa, NULL) == -1) {
+        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
+                      "sigaction(SIGPIPE, SIG_IGN) failed");
+        exit(1);
+    }
+}
+
 static void ngx_open_listening_sockets(ngx_log_t *log)
 {
     int           times, failed, reuseaddr, i;
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -5,6 +5,7 @@
 #include <ngx_log.h>
 #include <ngx_hunk.h>
 #include <ngx_alloc.h>
+#include <ngx_string.h>
 #include <ngx_server.h>
 
 typedef struct ngx_connection_s  ngx_connection_t;
@@ -38,8 +39,7 @@ struct ngx_connection_s {
     struct sockaddr  *sockaddr;
     socklen_t         socklen;
     size_t            addr;
-    char             *addr_text;
-    size_t            addr_textlen;
+    ngx_str_t         addr_text;
 
     ngx_hunk_t       *buffer;
     unsigned int      post_accept_timeout;
--- a/src/core/ngx_listen.h
+++ b/src/core/ngx_listen.h
@@ -14,8 +14,7 @@ typedef struct {
     struct sockaddr  *sockaddr;
     socklen_t         socklen;
     size_t            addr;
-    char             *addr_text;
-    size_t            addr_textlen;
+    ngx_str_t         addr_text;
 
     int           family;
     int           type;
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -74,7 +74,6 @@ void ngx_pre_thread(ngx_array_t *ls, ngx
         ngx_connections[fd].sockaddr = ngx_palloc(pool, s[i].socklen);
         ngx_connections[fd].addr = s[i].addr;
         ngx_connections[fd].addr_text = s[i].addr_text;
-        ngx_connections[fd].addr_textlen = s[i].addr_textlen;
         ngx_connections[fd].post_accept_timeout = s[i].post_accept_timeout;
 
         ngx_connections[fd].server = s[i].server;
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -54,7 +54,7 @@ int ngx_event_accept(ngx_event_t *ev)
         ngx_connections[s].family = cn->family;
         ngx_connections[s].socklen = cn->socklen;
         ngx_connections[s].addr = cn->addr;
-        ngx_connections[s].addr_textlen = cn->addr_textlen;
+        ngx_connections[s].addr_text.len = cn->addr_text.len;
         ngx_connections[s].post_accept_timeout = cn->post_accept_timeout;
 
         ngx_read_events[s].data = ngx_write_events[s].data
--- a/src/http/modules/ngx_http_event_proxy_handler.c
+++ b/src/http/modules/ngx_http_event_proxy_handler.c
@@ -65,8 +65,9 @@ static ngx_chain_t *ngx_http_proxy_creat
     ngx_chain_t      *chain;
     ngx_table_elt_t  *header;
 
-    /* "+ 4" is for "\r\n" after request line and at the header end */
-    len = r->request_line.len + 4;
+    /* 2 is for "\r\n" after request line
+       and 2 is for "\r\n" at the header end */
+    len = r->request_line.len + 2 + 2;
 
     /* "Connection: close\r\n" */
     len += sizeof(conn_close) - 1;
@@ -79,8 +80,8 @@ static ngx_chain_t *ngx_http_proxy_creat
         if (&header[i] == r->headers_in.connection)
             continue;
 
-        /* "+ 4" is for ": " and "\r\n" */
-        len += header[i].key.len + header[i].value.len + 4;
+        /* 2 is for ": " and 2 is for "\r\n" */
+        len += header[i].key.len + 2 + header[i].value.len + 2;
     }
 
     /* STUB */ len++;
@@ -320,6 +321,7 @@ static int ngx_http_proxy_read_response_
         ngx_http_proxy_process_status_line(r, p)
         ngx_http_proxy_process_reponse_header(r, p) */
 
+#if 0
     do {
         rc = (p->state_handler)(r, p);
 
@@ -329,6 +331,7 @@ static int ngx_http_proxy_read_response_
         /* rc == NGX_OK || rc == NGX_AGAIN */
 
     } while (p->header_in->pos.mem < p->header_in->last.mem);
+#endif
 
     ev->event_handler = ngx_http_proxy_read_response_body;
     if (p->header_in->end - p->header_in->last.mem == 0)
@@ -342,11 +345,11 @@ static int ngx_http_proxy_process_status
 {
     int  rc;
 
-    ngx_log_debug(r->connection->log, "STATUS: %d" _ p->status);
-
     rc = ngx_read_http_proxy_status_line(p);
 
-    ngx_log_debug(r->connection->log, "STATUS: %d" _ p->status);
+    if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
+        p->status = 200;
+    }
 
     if (rc == NGX_OK) {
         /* STUB */
@@ -365,6 +368,11 @@ static int ngx_http_proxy_process_status
     /* STUB */ return NGX_ERROR;
 }
 
+static int ngx_http_proxy_process_response_header(ngx_http_request_t *r,
+                                                  ngx_http_proxy_ctx_t *p)
+{
+}
+
 static int ngx_http_proxy_read_response_body(ngx_event_t *ev)
 {
     int     n;
@@ -560,8 +568,10 @@ fprintf(stderr, "state: %d, pos: %x, end
 
             ctx->status = ctx->status * 10 + ch - '0';
 
-            if (++ctx->status_count == 3)
+            if (++ctx->status_count == 3) {
                 state = sw_space_after_status;
+                ctx->status_line = p - 3;
+            }
 
             break;
 
@@ -569,7 +579,6 @@ fprintf(stderr, "state: %d, pos: %x, end
          case sw_space_after_status:
             switch (ch) {
             case ' ':
-                ctx->status_text = p - 1;
                 state = sw_status_text;
                 break;
             case CR:
--- a/src/http/modules/ngx_http_event_proxy_handler.h
+++ b/src/http/modules/ngx_http_event_proxy_handler.h
@@ -30,7 +30,7 @@ struct ngx_http_proxy_ctx_s {
     int          state;
     int          status;
     int          status_count;
-    char        *status_text;
+    char        *status_line;
     char        *request_end;
     int        (*state_handler)(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p);
 };
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -11,17 +11,24 @@
 
 
 static void *ngx_http_index_create_conf(ngx_pool_t *pool);
-static char *ngx_http_index_set_index(ngx_pool_t *p, void *conf, char *value);
+static void *ngx_http_index_merge_conf(ngx_pool_t *p,
+                                       void *parent, void *child);
+static char *ngx_http_index_set_index(ngx_pool_t *p, void *conf,
+                                      ngx_str_t *value);
 
 static ngx_command_t ngx_http_index_commands[];
 
 
 ngx_http_module_t  ngx_http_index_module = {
     NGX_HTTP_MODULE,
+
     NULL,                                  /* create server config */
     ngx_http_index_create_conf,            /* create location config */
     ngx_http_index_commands,               /* module directives */
+
     NULL,                                  /* init module */
+    NULL,                                  /* translate handler */
+
     NULL,                                  /* init output body filter */
 };
 
@@ -36,32 +43,32 @@ static ngx_command_t ngx_http_index_comm
 
 };
 
+
 int ngx_http_index_handler(ngx_http_request_t *r)
 {
-    int          index_len, i;
-    char        *name, *loc, *file;
+    int          i;
+    char        *name, *file;
+    ngx_str_t    loc, *index;
     ngx_err_t    err;
     ngx_fd_t     fd;
 
-    ngx_http_index_file_t  *index;
     ngx_http_index_conf_t  *cf;
 
     cf = (ngx_http_index_conf_t *)
                             ngx_get_module_loc_conf(r, ngx_http_index_module);
 
-    index_len = (*(r->uri_end - 1) == '/') ? cf->max_index_len : 0;
-
     ngx_test_null(name,
-                  ngx_palloc(r->pool, r->uri_end - r->uri_start + index_len
-                                      + r->server->doc_root_len),
+                  ngx_palloc(r->pool,
+                             r->server->doc_root_len + r->uri.len
+                             + cf->max_index_len),
                   NGX_HTTP_INTERNAL_SERVER_ERROR);
 
-    loc = ngx_cpystrn(name, r->server->doc_root, r->server->doc_root_len);
-    file = ngx_cpystrn(loc, r->uri_start, r->uri_end - r->uri_start + 1);
+    loc.data = ngx_cpystrn(name, r->server->doc_root, r->server->doc_root_len);
+    file = ngx_cpystrn(loc.data, r->uri.data, r->uri.len + 1);
 
-    index = (ngx_http_index_file_t *) cf->indices->elts;
+    index = (ngx_str_t *) cf->indices->elts;
     for (i = 0; i < cf->indices->nelts; i++) {
-        ngx_memcpy(file, index[i].name, index[i].len);
+        ngx_memcpy(file, index[i].data, index[i].len + 1);
 
         fd = ngx_open_file(name, NGX_FILE_RDONLY);
         if (fd == -1) {
@@ -75,15 +82,18 @@ int ngx_http_index_handler(ngx_http_requ
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        r->filename = name; 
+        r->filename.len = r->server->doc_root_len + r->uri.len + index[i].len;
+        r->filename.data = name; 
         r->fd = fd; 
 
+        loc.len = r->uri.len + index[i].len;
         return ngx_http_internal_redirect(r, loc);
     }
 
     return NGX_DECLINED;
 }
 
+
 static void *ngx_http_index_create_conf(ngx_pool_t *pool)
 {
     ngx_http_index_conf_t  *conf;
@@ -91,38 +101,42 @@ static void *ngx_http_index_create_conf(
     ngx_test_null(conf, ngx_pcalloc(pool, sizeof(ngx_http_index_conf_t)), NULL);
 
     ngx_test_null(conf->indices,
-                  ngx_create_array(pool, sizeof(ngx_http_index_file_t), 3),
+                  ngx_create_array(pool, sizeof(ngx_str_t), 3),
                   NULL);
 
     return conf;
 }
 
+
 static void *ngx_http_index_merge_conf(ngx_pool_t *p, void *parent, void *child)
 {
     ngx_http_index_conf_t *prev = (ngx_http_index_conf_t *) parent;
     ngx_http_index_conf_t *conf = (ngx_http_index_conf_t *) child;
-    ngx_http_index_file_t *index;
+    ngx_str_t  *index;
 
     if (conf->max_index_len == 0) {
         if (prev->max_index_len != 0)
             return prev;
 
         ngx_test_null(index, ngx_push_array(conf->indices), NULL);
-        index->name = NGX_HTTP_INDEX;
-        conf->max_index_len = index->len = sizeof(NGX_HTTP_INDEX) + 1;
+        index->len = sizeof(NGX_HTTP_INDEX) - 1;
+        index->data = NGX_HTTP_INDEX;
+        conf->max_index_len = sizeof(NGX_HTTP_INDEX);
     }
 
     return conf;
 }
 
-static char *ngx_http_index_set_index(ngx_pool_t *p, void *conf, char *value)
+
+static char *ngx_http_index_set_index(ngx_pool_t *p, void *conf,
+                                      ngx_str_t *value)
 {
     ngx_http_index_conf_t *cf = (ngx_http_index_conf_t *) conf;
-    ngx_http_index_file_t *index;
+    ngx_str_t  *index;
 
     ngx_test_null(index, ngx_push_array(cf->indices), NULL);
-    index->name = value;
-    index->len = strlen(value) + 1;
+    index->len = value->len;
+    index->data = value->data;
 
     if (cf->max_index_len < index->len)
         cf->max_index_len = index->len;
--- a/src/http/modules/ngx_http_index_handler.h
+++ b/src/http/modules/ngx_http_index_handler.h
@@ -14,11 +14,6 @@ typedef struct {
     size_t        max_index_len;
 } ngx_http_index_conf_t;
 
-typedef struct {
-    char   *name;
-    size_t  len;
-} ngx_http_index_file_t;
-
 
 extern ngx_http_module_t  ngx_http_index_module;
 
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -40,11 +40,13 @@ int ngx_http_static_handler(ngx_http_req
     ctx = r->connection->log->data;
     ctx->action = "sending response";
 
-    r->fd = ngx_open_file(r->filename, NGX_FILE_RDONLY);
+    if (r->fd != -1)
+        r->fd = ngx_open_file(r->filename.data, NGX_FILE_RDONLY);
+
     if (r->fd == -1) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
                       "ngx_http_static_handler: "
-                      ngx_open_file_n " %s failed", r->filename);
+                      ngx_open_file_n " %s failed", r->filename.data);
 
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -52,7 +54,7 @@ int ngx_http_static_handler(ngx_http_req
     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);
+                      ngx_stat_fd_n " %s failed", r->filename.data);
 
         /* close fd */
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -64,25 +66,35 @@ int ngx_http_static_handler(ngx_http_req
     r->headers_out.last_modified = ngx_file_mtime(r->fileinfo);
 */
 
+    ngx_test_null(r->headers_out.content_type,
+                  ngx_push_table(r->headers_out.headers),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+    r->headers_out.content_type->key.len = 12;
+    r->headers_out.content_type->key.data = "Content-Type";
+
     /* STUB */
-    if (r->exten) {
-        if (strcasecmp(r->exten, "html") == 0)
-            r->headers_out.content_type = "text/html; charset=koi8-r";
-        else if (strcasecmp(r->exten, "gif") == 0)
-            r->headers_out.content_type = "image/gif";
-        else if (strcasecmp(r->exten, "jpg") == 0)
-            r->headers_out.content_type = "image/jpeg";
-        else if (strcasecmp(r->exten, "pdf") == 0)
-            r->headers_out.content_type = "application/pdf";
+    if (r->exten.len) {
+        if (strcasecmp(r->exten.data, "html") == 0) {
+            r->headers_out.content_type->value.len = 25;
+            r->headers_out.content_type->value.data =
+                                                   "text/html; charset=koi8-r";
+        } else if (strcasecmp(r->exten.data, "gif") == 0) {
+            r->headers_out.content_type->value.len = 9;
+            r->headers_out.content_type->value.data = "image/gif";
+        } else if (strcasecmp(r->exten.data, "jpg") == 0) {
+            r->headers_out.content_type->value.len = 10;
+            r->headers_out.content_type->value.data = "image/jpeg";
+        }
 
     } else {
-        r->headers_out.content_type = "text/html; charset=koi8-r";
+        r->headers_out.content_type->value.len = 25;
+        r->headers_out.content_type->value.data = "text/html; charset=koi8-r";
     }
 
     /* STUB */
     rc = ngx_http_header_filter(r);
 /*
-    rc = ngx_send_http_header(r->headers_out);
+    rc = ngx_send_http_header(r);
 */
     if (r->header_only)
         return rc;
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -66,8 +66,8 @@ int ngx_http_init(ngx_pool_t *pool, ngx_
     ls->sockaddr = (struct sockaddr *) &addr;
     ls->socklen = sizeof(struct sockaddr_in);
     ls->addr = offsetof(struct sockaddr_in, sin_addr);
-    ls->addr_text = addr_text;
-    ls->addr_textlen = INET_ADDRSTRLEN;
+    ls->addr_text.len = INET_ADDRSTRLEN;
+    ls->addr_text.data = addr_text;
     ls->backlog = -1;
     ls->post_accept_timeout = 10000;
     ls->nonblocking = 1;
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -12,6 +12,8 @@
 #include <ngx_config_command.h>
 
 
+#define NGX_HTTP_VERSION_10       1000
+
 #define NGX_HTTP_GET   1
 #define NGX_HTTP_HEAD  2
 #define NGX_HTTP_POST  3
@@ -73,23 +75,29 @@ typedef struct {
 } ngx_http_headers_in_t;
 
 typedef struct {
-    int     status;
-    int     connection;
-    off_t   content_length;
-    char   *location;
-    char   *content_type;
-    char   *charset;
-    char   *etag;
-    char   *server;
-    time_t  date;
-    time_t  last_modified;
+    int               status;
+    ngx_str_t         status_line;
+
+    ngx_table_elt_t  *server;
+    ngx_table_elt_t  *date;
+    ngx_table_elt_t  *content_type;
+    ngx_table_elt_t  *location;
+    ngx_table_elt_t  *last_modified;
+
+    ngx_table_t      *headers;
+
+    off_t             content_length;
+    char             *charset;
+    char             *etag;
+    time_t            date_time;
+    time_t            last_modified_time;
 } ngx_http_headers_out_t;
 
 typedef struct ngx_http_request_s ngx_http_request_t;
 
 struct ngx_http_request_s {
-    char  *filename;
-    char  *location;
+    ngx_str_t  filename;
+
     ngx_fd_t  fd;
 
     void  **ctx;
@@ -116,8 +124,8 @@ struct ngx_http_request_s {
     int    http_minor;
 
     ngx_str_t  request_line;
-    char  *uri;
-    char  *exten;
+    ngx_str_t  uri;
+    ngx_str_t  exten;
     ngx_http_request_t *main;
 
     ngx_connection_t  *connection;
@@ -132,7 +140,6 @@ struct ngx_http_request_s {
     unsigned  lingering_close:1;
 
     unsigned  header_read:1;
-    unsigned  process_header:1;
     unsigned  header_timeout:1;
 
     unsigned  logging:1;
@@ -165,10 +172,15 @@ typedef struct {
 
 typedef struct {
     int               index;
+
     void           *(*create_srv_conf)(ngx_pool_t *p);
     void           *(*create_loc_conf)(ngx_pool_t *p);
     ngx_command_t    *commands;
+
     int             (*init_module)(ngx_pool_t *p);
+
+    int             (*translate_handler)(ngx_http_request_t *r);
+
     int             (*init_output_body_filter)(int (**next_filter)
                                      (ngx_http_request_t *r, ngx_chain_t *ch));
 } ngx_http_module_t;
--- a/src/http/ngx_http_config.c
+++ b/src/http/ngx_http_config.c
@@ -100,13 +100,16 @@ ngx_http_write_filter_set_stub(ngx_pool_
 ngx_http_index_set_stub(ngx_pool_t *pool, ngx_http_module_t **modules)
 {
     int i;
+    ngx_str_t index;
     ngx_command_t *cmd;
 
     for (i = 0; modules[i]; i++) {
         if (modules[i] == &ngx_http_index_module) {
             for (cmd = modules[i]->commands; cmd->name; cmd++) {
                 if (strcmp(cmd->name, "index") == 0) {
-                    cmd->set(pool, ngx_loc_conf[i], "index.html");
+                    index.len = sizeof("index.html") - 1;
+                    index.data = "index.html";
+                    cmd->set(pool, ngx_loc_conf[i], &index);
                 }
             }
         }
--- a/src/http/ngx_http_core.c
+++ b/src/http/ngx_http_core.c
@@ -1,13 +1,21 @@
 
 #include <ngx_config.h>
+#include <ngx_core.h>
 #include <ngx_config_command.h>
 #include <ngx_http.h>
 #include <ngx_http_core.h>
 #include <ngx_http_config.h>
 
+/* STUB */
+#include <ngx_http_output_filter.h>
+int ngx_http_static_handler(ngx_http_request_t *r);
+int ngx_http_index_handler(ngx_http_request_t *r);
+int ngx_http_proxy_handler(ngx_http_request_t *r);
+/**/
 
 static void *ngx_http_core_create_srv_conf(ngx_pool_t *pool);
 static void *ngx_http_core_create_loc_conf(ngx_pool_t *pool);
+static int ngx_http_core_translate_handler(ngx_http_request_t *r);
 
 
 static ngx_command_t ngx_http_core_commands[];
@@ -15,10 +23,14 @@ static ngx_command_t ngx_http_core_comma
 
 ngx_http_module_t  ngx_http_core_module = {
     NGX_HTTP_MODULE,
+
     ngx_http_core_create_srv_conf,         /* create server config */
     ngx_http_core_create_loc_conf,         /* create location config */
     ngx_http_core_commands,                /* module directives */
-    NULL,                                  /* init module */
+
+    /* STUB */ NULL,                                  /* init module */
+    ngx_http_core_translate_handler,       /* translate handler */
+
     NULL                                   /* init output body filter */
 };
 
@@ -35,6 +47,168 @@ static ngx_command_t ngx_http_core_comma
 };
 
 
+int ngx_http_handler(ngx_http_request_t *r)
+{
+    int  rc, i;
+
+    r->connection->unexpected_eof = 0;
+    r->lingering_close = 1;
+    r->keepalive = 1;
+
+#if 1
+    r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
+#endif
+
+    /* run translation phase */
+    for (i = 0; ngx_http_modules[i]; i++) {
+        if (ngx_http_modules[i]->translate_handler) {
+            rc = ngx_http_modules[i]->translate_handler(r);
+            if (rc == NGX_OK)
+                break;
+
+            if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
+                return ngx_http_special_response(r, rc);
+        }
+    }
+
+    rc = r->handler(r);
+
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
+        return ngx_http_special_response(r, rc);
+
+    return rc;
+}
+
+
+static int ngx_http_core_translate_handler(ngx_http_request_t *r)
+{
+    char      *loc, *last;
+    ngx_err_t  err;
+    ngx_table_elt_t  *h;
+
+    /* TODO: find location conf */
+
+    if (r->uri.data[r->uri.len - 1] == '/') {
+        /* TODO: find index handler */
+        /* STUB */ r->handler = ngx_http_index_handler;
+
+        return NGX_OK;
+    }
+
+    r->filename.len = r->server->doc_root_len + r->uri.len + 2;
+
+    ngx_test_null(r->filename.data,
+                  ngx_palloc(r->pool, r->filename.len + 1),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+    loc = ngx_cpystrn(r->filename.data, r->server->doc_root,
+                      r->server->doc_root_len);
+    last = ngx_cpystrn(loc, r->uri.data, r->uri.len + 1);
+
+    ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->filename.data);
+
+    if (ngx_file_type(r->filename.data, &r->fileinfo) == -1) {
+        err = ngx_errno;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
+                      ngx_file_type_n " %s failed", r->filename.data);
+
+        if (err == NGX_ENOENT)
+            return NGX_HTTP_NOT_FOUND;
+        else
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (ngx_is_dir(r->fileinfo)) {
+        ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->filename.data);
+
+        /* BROKEN: need to include server name */
+
+        ngx_test_null(h, ngx_push_table(r->headers_out.headers),
+                      NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+        *last++ = '/';
+        *last = '\0';
+        h->key.len = 8;
+        h->key.data = "Location" ;
+        h->value.len = last - loc;
+        h->value.data = loc;
+        r->headers_out.location = h;
+
+        return NGX_HTTP_MOVED_PERMANENTLY;
+    }
+
+    /* TODO: r->handler = loc_conf->default_handler; */
+    /* STUB */ r->handler = ngx_http_static_handler;
+
+    return NGX_OK;
+}
+
+
+
+int ngx_http_redirect(ngx_http_request_t *r, int redirect)
+{
+    /* STUB */
+
+    /* log request */
+
+    return ngx_http_close_request(r);
+}
+
+
+int ngx_http_error(ngx_http_request_t *r, int error) 
+{
+    /* STUB */
+    ngx_log_debug(r->connection->log, "http error: %d" _ error);
+
+    /* log request */
+
+    return ngx_http_close_request(r);
+}
+
+
+int ngx_http_close_request(ngx_http_request_t *r)
+{
+    ngx_assert((r->fd != -1), /* void */; , r->connection->log,
+               "file already closed");
+
+    if (r->fd != -1) {
+        if (ngx_close_file(r->fd) == -1)
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+                          ngx_close_file_n " failed");
+    }
+
+/*
+    if (r->logging)
+        ngx_http_log_request(r);
+*/
+
+    ngx_destroy_pool(r->pool);
+
+    ngx_log_debug(r->connection->log, "http close");
+
+    ngx_del_timer(r->connection->read);
+    ngx_del_timer(r->connection->write);
+
+    return NGX_DONE;
+}
+
+
+int ngx_http_internal_redirect(ngx_http_request_t *r, ngx_str_t uri)
+{
+    ngx_log_debug(r->connection->log, "internal redirect: '%s'" _ uri.data);
+
+    r->uri.len = uri.len;
+    r->uri.data = uri.data;
+
+    /* NEEDED ? */
+    r->uri_start = uri.data;
+    r->uri_end = uri.data + uri.len;
+    /**/
+
+    return ngx_http_handler(r);
+}
+
+
 static void *ngx_http_core_create_srv_conf(ngx_pool_t *pool)
 {
     ngx_http_core_srv_conf_t *conf;
--- a/src/http/ngx_http_event.c
+++ b/src/http/ngx_http_event.c
@@ -22,22 +22,24 @@
 int ngx_http_static_handler(ngx_http_request_t *r);
 int ngx_http_index_handler(ngx_http_request_t *r);
 int ngx_http_proxy_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);
-static int ngx_http_process_request(ngx_event_t *ev);
+static int ngx_http_process_request_header(ngx_event_t *ev);
 
 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_headers(ngx_http_request_t *r);
 static int ngx_http_process_request_header_line(ngx_http_request_t *r);
 
+static int ngx_http_event_handler(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_event_handler(ngx_http_request_t *r);
-static int ngx_http_handler(ngx_http_request_t *r);
+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);
@@ -45,11 +47,13 @@ static int ngx_http_set_lingering_close(
 static int ngx_http_keepalive_handler(ngx_event_t *ev);
 static int ngx_http_lingering_close(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);
+#if 0
+int ngx_http_special_response(ngx_http_request_t *r, int error);
+int ngx_http_redirect(ngx_http_request_t *r, int redirect);
+int ngx_http_error(ngx_http_request_t *r, int error);
+int ngx_http_close_request(ngx_http_request_t *r);
+#endif
 
-static int ngx_http_close_request(ngx_http_request_t *r);
 static int ngx_http_close_connection(ngx_event_t *ev);
 static size_t ngx_http_log_error(void *data, char *buf, size_t len);
 
@@ -99,19 +103,22 @@ int ngx_http_init_connection(ngx_connect
     ngx_memcpy(addr, c->sockaddr, c->socklen);
     c->sockaddr = addr;
 
-    ngx_test_null(c->addr_text, ngx_palloc(c->pool, c->addr_textlen),
+    ngx_test_null(c->addr_text.data, ngx_palloc(c->pool, c->addr_text.len),
                   NGX_ERROR);
+
+    /* STUB: should be ngx_inet_ntop() */
 #if (WIN32)
-    c->addr_text = inet_ntoa((struct in_addr *)
+    c->addr_text.data = inet_ntoa((struct in_addr *)
                                               ((char *)c->sockaddr + c->addr));
 #else
     inet_ntop(c->family, (char *)c->sockaddr + c->addr,
-              c->addr_text, c->addr_textlen);
+              c->addr_text.data, c->addr_text.len);
 #endif
+    /**/
 
     ngx_test_null(ctx, ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)),
                   NGX_ERROR);
-    ctx->client = c->addr_text;
+    ctx->client = c->addr_text.data;
     ctx->action = "reading client request line";
     c->log->data = ctx;
     c->log->handler = ngx_http_log_error;
@@ -121,6 +128,7 @@ int ngx_http_init_connection(ngx_connect
         return ngx_http_init_request(ev);
     } else {
 #endif
+        /* STUB: post_accept_timeout should be in http_conf */
         ngx_add_timer(ev, c->post_accept_timeout);
 #if (USE_KQUEUE)
         return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
@@ -159,8 +167,10 @@ static int ngx_http_init_request(ngx_eve
     r->connection = c;
     r->server = srv;
 
+    /* STUB */
     r->srv_conf = ngx_srv_conf;
     r->loc_conf = ngx_loc_conf;
+    /**/
 
     if (c->buffer == NULL) {
         ngx_test_null(c->buffer,
@@ -179,16 +189,15 @@ static int ngx_http_init_request(ngx_eve
     ngx_test_null(r->ctx, ngx_pcalloc(r->pool, sizeof(void *) * ngx_max_module),
                   ngx_http_close_request(r));
 
-    ev->event_handler = ngx_http_process_request;
+    ev->event_handler = ngx_http_process_request_header;
     r->state_handler = ngx_http_process_request_line;
-    r->process_header = 1;
     r->header_timeout = 1;
 
-    return ngx_http_process_request(ev);
+    return ngx_http_process_request_header(ev);
 }
 
 
-static int ngx_http_process_request(ngx_event_t *ev)
+static int ngx_http_process_request_header(ngx_event_t *ev)
 {
     int n, rc;
     ngx_connection_t *c ;
@@ -213,6 +222,8 @@ static int ngx_http_process_request(ngx_
             if (r->header_timeout) {
                 r->header_timeout = 0;
                 ngx_del_timer(ev);
+                /* STUB: r->server->header_timeout
+                         OR r->srv_conf->header_timeout ? */
                 ngx_add_timer(ev, r->server->header_timeout);
             }
             return NGX_AGAIN;
@@ -224,9 +235,8 @@ static int ngx_http_process_request(ngx_
         ngx_log_debug(ev->log, "http read %d" _ n);
 
         if (n == 0) {
-            if (c->unexpected_eof)
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client prematurely closed connection");
+            ngx_log_error(NGX_LOG_INFO, c->log, 0,
+                          "client has prematurely closed connection");
             return ngx_http_close_request(r);
         }
 
@@ -235,7 +245,7 @@ static int ngx_http_process_request(ngx_
 
     /* state_handlers are called in following order:
         ngx_http_process_request_line(r)
-        ngx_http_process_request_header(r) */
+        ngx_http_process_request_headers(r) */
 
     do {
         rc = (r->state_handler)(r);
@@ -243,10 +253,7 @@ static int ngx_http_process_request(ngx_
         if (rc == NGX_ERROR)
             return rc;
 
-        /* rc == NGX_OK || rc == NGX_AGAIN */
-
-    } while (r->process_header
-             && r->header_in->pos.mem < r->header_in->last.mem);
+    } while (rc == NGX_AGAIN && r->header_in->pos.mem < r->header_in->last.mem);
 
     if (r->header_timeout) {
         r->header_timeout = 0;
@@ -254,7 +261,10 @@ static int ngx_http_process_request(ngx_
         ngx_add_timer(ev, r->server->header_timeout);
     }
 
-    return rc;
+    if (rc == NGX_OK)
+        return ngx_http_event_handler(r);
+    else
+        return rc;
 }
 
 
@@ -270,10 +280,10 @@ static int ngx_http_process_request_line
     c = r->connection;
 
     if (rc == NGX_OK) {
-        len = r->uri_end - r->uri_start + 1;
-        ngx_test_null(r->uri, ngx_palloc(r->pool, len),
+        r->uri.len = r->uri_end - r->uri_start;
+        ngx_test_null(r->uri.data, ngx_palloc(r->pool, r->uri.len + 1),
                       ngx_http_close_request(r));
-        ngx_cpystrn(r->uri, r->uri_start, len);
+        ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
 
         r->request_line.len = r->request_end - r->header_in->start;
         ngx_test_null(r->request_line.data,
@@ -299,27 +309,31 @@ static int ngx_http_process_request_line
         /* */
 
         if (r->uri_ext) {
-            ngx_test_null(r->exten,
-                          ngx_palloc(r->pool, r->uri_end - r->uri_ext + 1), 
+            r->exten.len = r->uri_end - r->uri_ext;
+            ngx_test_null(r->exten.data,
+                          ngx_palloc(r->pool, r->exten.len + 1), 
                           ngx_http_close_request(r));
-            ngx_cpystrn(r->exten, r->uri_ext, r->uri_end - r->uri_ext + 1);
+            ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
         }
 
         ngx_log_debug(r->connection->log, "HTTP: %d, %d, %s %s" _
-                      r->method _ r->http_version _ r->uri _ r->exten);
+                      r->method _ r->http_version _
+                      r->uri.data _ r->exten.data);
 
         if (r->http_version == 9)
-            return ngx_http_event_handler(r);
+            return NGX_OK;
 
         /* TODO: check too long URI - no space for header, compact buffer */
 
         r->headers_in.headers = ngx_create_table(r->pool, 10);
+        /* THINK: when to create out.headers ? */
+        r->headers_out.headers = ngx_create_table(r->pool, 10);
 
-        r->state_handler = ngx_http_process_request_header;
+        r->state_handler = ngx_http_process_request_headers;
         ctx = r->connection->log->data;
         ctx->action = "reading client request headers";
 
-        return NGX_OK;
+        return NGX_AGAIN;
     }
 
     if (r->header_in->last.mem >= r->header_in->end) {
@@ -342,13 +356,13 @@ static int ngx_http_process_request_line
 }
 
 
-static int ngx_http_process_request_header(ngx_http_request_t *r)
+static int ngx_http_process_request_headers(ngx_http_request_t *r)
 {
     int rc;
     ngx_http_log_ctx_t  *ctx;
 
     for ( ;; ) {
-        rc = ngx_read_http_header_line(r);
+        rc = ngx_read_http_header_line(r, r->header_in);
 
         /* TODO: check too long header, compact buffer */
 
@@ -358,7 +372,7 @@ static int ngx_http_process_request_head
 
         } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
             ngx_log_debug(r->connection->log, "HTTP header done");
-            return ngx_http_event_handler(r);
+            return NGX_OK;
 
         } else if (rc == NGX_AGAIN) {
             return NGX_AGAIN;
@@ -408,90 +422,16 @@ static int ngx_http_process_request_head
 }
 
 
-/* ******************** */
-
-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);
-
-    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 == NGX_ERROR)
-        return NGX_ERROR;
-
-    if (n == NGX_AGAIN)
-        return NGX_OK;
-
-    r->client_content_length -= n;
-    /* XXX: what if r->client_content_length == 0 ? */
-    return NGX_OK;
-}
-
-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_event_handler(ngx_http_request_t *r)
 {
     int rc;
     ngx_msec_t  timeout;
 
-    ngx_log_debug(r->connection->log, "UA: '%s: %s'" _
-                  r->headers_in.user_agent->key.data _
-                  r->headers_in.user_agent->value.data);
+    ngx_del_timer(r->connection->read);
+    r->header_timeout = 0;
+
+    r->state_handler = NULL;
+    r->connection->read->event_handler = ngx_http_block_read;
 
     rc = ngx_http_handler(r);
 
@@ -553,22 +493,105 @@ static int ngx_http_event_handler(ngx_ht
     r->connection->read->event_handler = ngx_http_keepalive_handler;
 }
 
-static int ngx_http_handler(ngx_http_request_t *r)
+
+static int ngx_http_block_read(ngx_event_t *ev)
+{
+    ngx_log_debug(ev->log, "http read blocked");
+
+    ev->blocked = 1;
+    return ngx_del_event(ev, NGX_READ_EVENT);
+}
+
+
+
+/* FIND PLACE ******************** */
+
+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);
+
+    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 == NGX_ERROR)
+        return NGX_ERROR;
+
+    if (n == NGX_AGAIN)
+        return NGX_OK;
+
+    r->client_content_length -= n;
+    /* XXX: what if r->client_content_length == 0 ? */
+    return NGX_OK;
+}
+
+
+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
+int ngx_http_handler(ngx_http_request_t *r)
 {
     int  rc;
 
-    ngx_del_timer(r->connection->read);
-    r->header_timeout = 0;
-
-    r->process_header = 0;
-    r->state_handler = NULL;
     r->connection->unexpected_eof = 0;
     r->lingering_close = 1;
 
-    r->connection->read->event_handler = ngx_http_block_read;
-
     /* STUB: should find handler */
-#if 0
+#if 1
     r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
 #endif
     rc = ngx_http_set_default_handler(r);
@@ -580,23 +603,16 @@ static int ngx_http_handler(ngx_http_req
 
     return rc;
 }
-
-int ngx_http_internal_redirect(ngx_http_request_t *r, char *uri)
-{
-    ngx_log_debug(r->connection->log, "internal redirect: '%s'" _ uri);
+#endif
 
-    r->uri = uri;
-    r->uri_start = uri;
-    r->uri_end = uri + strlen(uri);
-    return ngx_http_handler(r);
-}
 
+#if 0
 static int ngx_http_set_default_handler(ngx_http_request_t *r)
 {
-    int   err, rc;
-    char *name, *loc, *file;
+    ngx_err_t  err;
+    char      *name, *loc, *file;
 
-#if 1
+#if 0
     /* STUB */
     r->handler = ngx_http_proxy_handler;
     return NGX_OK;
@@ -650,15 +666,7 @@ static int ngx_http_set_default_handler(
 
     return NGX_OK;
 }
-
-
-static int ngx_http_block_read(ngx_event_t *ev)
-{
-    ngx_log_debug(ev->log, "http read blocked");
-
-    ev->blocked = 1;
-    return ngx_del_event(ev, NGX_READ_EVENT);
-}
+#endif
 
 
 static int ngx_http_writer(ngx_event_t *ev)
@@ -726,6 +734,7 @@ static int ngx_http_writer(ngx_event_t *
     c->read->event_handler = ngx_http_keepalive_handler;
 }
 
+
 static int ngx_http_set_lingering_close(ngx_http_request_t *r)
 {
     r->lingering_time = ngx_time() + r->server->lingering_time;
@@ -842,111 +851,6 @@ static int ngx_http_lingering_close(ngx_
 }
 
 
-static int ngx_http_special_response(ngx_http_request_t *r, int error)
-{
-    return ngx_http_error(r, error);
-}
-
-
-static int ngx_http_redirect(ngx_http_request_t *r, int redirect)
-{
-    /* STUB */
-
-    /* log request */
-
-    return ngx_http_close_request(r);
-}
-
-
-static int ngx_http_error(ngx_http_request_t *r, int error)
-{
-    /* STUB */
-    ngx_log_debug(r->connection->log, "http error: %d" _ error);
-
-    /* log request */
-
-    return ngx_http_close_request(r);
-}
-
-#if 0
-
-static int ngx_process_http_request(ngx_http_request_t *r)
-{
-    int fd;
-    struct stat sb;
-    ngx_http_header_out_t  *header_out;
-    ngx_chunk_t            *header, *ch;
-
-    int index = (*(r->uri_end - 1) == '/') ? sizeof(NGX_INDEX) : 1;
-    char *name = ngx_palloc(r->pool,
-                           r->uri_end - r->uri_start + strlen(ngx_root) + index);
-    strcpy(name, ngx_root);
-    strcat(name, r->uri_start);
-    if (*(r->uri_end - 1) == '/')
-        strcat(name, NGX_INDEX);
-
-    ngx_log_debug(r->connection->log, "HTTP URI: '%s'", name);
-
-    if ((fd = open(name, O_RDONLY)) == -1) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, errno,
-                     "open %s failed", name);
-        return -1;
-    }
-
-    if (fstat(fd, &sb) == -1) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, errno,
-                     "fstat %s failed", name);
-        return -1;
-    }
-
-    header_out = ngx_palloc(r->pool, sizeof(ngx_http_header_out_t));
-
-    header_out->status = NGX_HTTP_OK;
-    header_out->content_length = sb.st_size;
-    header_out->last_modified = sb.st_mtime;
-    header_out->content_type = "text/html";
-    header_out->charset = "koi8-r";
-    header_out->date = time(NULL);
-    header_out->connection = NGX_HTTP_CONN_CLOSE;
-
-/*
-    header_out->connection = NGX_HTTP_CONN_KEEP_ALIVE;
-    r->connection->read->event_handler = ngx_http_init_request;
-*/
-
-    header = ngx_http_header(r, header_out);
-    ch = ngx_palloc(r->pool, sizeof(ngx_chunk_t));
-    ch->ident = fd;
-    ch->offset = 0;
-    ch->size = sb.st_size;
-    ch->next = NULL;
-    header->next = ch;
-
-    ngx_event_write(r->connection, header);
-
-    return 0;
-}
-
-#endif
-
-static int ngx_http_close_request(ngx_http_request_t *r)
-{
-/*
-    if (r->logging)
-        ngx_http_log_request(r);
-*/
-
-    ngx_destroy_pool(r->pool);
-
-    ngx_log_debug(r->connection->log, "http close");
-
-    ngx_del_timer(r->connection->read);
-    ngx_del_timer(r->connection->write);
-
-    return NGX_DONE;
-}
-
-
 static int ngx_http_close_connection(ngx_event_t *ev)
 {
     int    i, len;
--- a/src/http/ngx_http_get_time.c
+++ b/src/http/ngx_http_get_time.c
@@ -9,5 +9,5 @@ ngx_http_get_time(char *buf, time_t t)
     struct tm *tp;
 
     tp = gmtime(&t);
-    return strftime(buf, 31, "%a, %d %b %Y %H:%M:%S GMT", tp);
+    return strftime(buf, 30, "%a, %d %b %Y %H:%M:%S GMT", tp);
 }
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -4,83 +4,187 @@
 #include <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_string.h>
+#include <ngx_table.h>
 #include <ngx_hunk.h>
 #include <ngx_http.h>
 
 
-typedef struct {
-    int    len;
-    char  *line;
-} line;
+#if 0
+
+ngx_http_module_t  ngx_http_header_filter_module = {
+    NGX_HTTP_MODULE,
+
+    NULL,                                  /* create server config */
+    NULL,                                  /* create location config */
+    NULL,                                  /* module directives */
+
+    NULL,                                  /* init module */
+    NULL,                                  /* translate handler */
+
+    ngx_http_header_filter_init            /* init output header filter */
+    NULL                                   /* init output body filter */
+};
+
+#endif
 
 
-static line http_codes[] = {
-    { 6, "200 OK" }
+static char server_string[] = "Server: " NGINX_VER CRLF;
+
+
+static ngx_str_t http_codes[] = {
+    { 6,  "200 OK" },
+
+    { 21, "301 Moved Permanently" },
+
+    { 15, "400 Bad Request" },
+    { 0,  NULL },
+    { 0,  NULL },
+    { 13, "403 Forbidden" },
+    { 13, "404 Not Found" }
 };
 
 
 
 int ngx_http_header_filter(ngx_http_request_t *r)
 {
-    int  status;
-    ngx_hunk_t   *h;
-    ngx_chain_t  *ch;
+    int  len, status, i;
+    ngx_hunk_t       *h;
+    ngx_chain_t      *ch;
+    ngx_table_elt_t  *header;
+
+    if (r->http_version < NGX_HTTP_VERSION_10)
+        return NGX_OK;
+
+    /* 9 is for "HTTP/1.1 ", 2 is for trailing "\r\n"
+       and 2 is for end of header */
+    len = 9 + 2 + 2;
 
-    ngx_test_null(h, ngx_create_temp_hunk(r->pool, 1024, 0, 64),
-                  NGX_ERROR);
+    /* status line */
+    if (r->headers_out.status_line.len) {
+        len += r->headers_out.status_line.len;
+    } else {
+        if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY)
+            status = r->headers_out.status - NGX_HTTP_OK;
 
-    status = r->headers_out.status - NGX_HTTP_OK;
+        else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST)
+            status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY + 1;
+
+        else
+            status = r->headers_out.status - NGX_HTTP_BAD_REQUEST + 1 + 1;
 
-    ngx_memcpy(h->last.mem, "HTTP/1.1 ", 9);
-    h->last.mem += 9;
-    ngx_memcpy(h->last.mem, http_codes[status].line, http_codes[status].len);
-    h->last.mem += http_codes[status].len;
-    *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+        len += http_codes[status].len;
+    }
+
+    if (r->headers_out.server && r->headers_out.server->key.len) {
+        len += r->headers_out.server->key.len
+               + r->headers_out.server->value.len + 2;
+    } else {
+        len += sizeof(server_string) - 1;
+    }
 
-#if 1
-    r->keepalive = 1;
-    ngx_memcpy(h->last.mem, "Connection: keep-alive" CRLF, 24);
-    h->last.mem += 24;
+    if (r->headers_out.date && r->headers_out.date->key.len) {
+        len += r->headers_out.date->key.len
+               + r->headers_out.date->value.len + 2;
+    } else {
+        /* "Date: ... \r\n"; */
+        len += 37;
+    }
+
+    /* 2^64 is 20 characters */
+    if (r->headers_out.content_length >= 0)
+        len += 48;
+
+#if 0
+    if (r->headers_out.content_type.len)
+        len += r->headers_out.content_type.len + 16;
 #endif
 
-    ngx_memcpy(h->last.mem, "Date: ", 6);
-    h->last.mem += 6;
-    h->last.mem += ngx_http_get_time(h->last.mem, time(NULL));
+    if (r->keepalive)
+        len += 24;
+    else
+        len += 19;
+
+    header = (ngx_table_elt_t *) r->headers_out.headers->elts;
+    for (i = 0; i < r->headers_out.headers->nelts; i++) {
+        if (header[i].key.len == 0)
+            continue;
+
+        len += header[i].key.len + 2 + header[i].value.len + 2;
+    }
+
+    ngx_test_null(h, ngx_create_temp_hunk(r->pool, len, 0, 64), NGX_ERROR);
+
+    /* "HTTP/1.1 " */
+    ngx_memcpy(h->last.mem, "HTTP/1.1 ", 9);
+    h->last.mem += 9;
+
+    /* status line */
+    if (r->headers_out.status_line.len) {
+        ngx_memcpy(h->last.mem, r->headers_out.status_line.data,
+                   r->headers_out.status_line.len);
+        h->last.mem += r->headers_out.status_line.len;
+
+    } else {
+        ngx_memcpy(h->last.mem, http_codes[status].data,
+                   http_codes[status].len);
+        h->last.mem += http_codes[status].len;
+    }
     *(h->last.mem++) = CR; *(h->last.mem++) = LF;
 
+    if (!(r->headers_out.server && r->headers_out.server->key.len)) {
+        ngx_memcpy(h->last.mem, server_string, sizeof(server_string) - 1);
+        h->last.mem += sizeof(server_string) - 1;
+    }
+
+    if (!(r->headers_out.date && r->headers_out.date->key.len)) {
+        ngx_memcpy(h->last.mem, "Date: ", 6);
+        h->last.mem += 6;
+        h->last.mem += ngx_http_get_time(h->last.mem, time(NULL));
+        *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+    }
+
     /* 2^64 is 20 characters  */
-    if (r->headers_out.content_length)
-        h->last.mem += ngx_snprintf(h->last.mem, 49, "Content-Length: %d" CRLF,
+    if (r->headers_out.content_length >= 0)
+        h->last.mem += ngx_snprintf(h->last.mem, 49, "Content-Length: %u" CRLF,
                                     r->headers_out.content_length);
 
-    /* check */
-
-    if (r->headers_out.content_type)
-        h->last.mem += ngx_snprintf(h->last.mem, 100, "Content-Type: %s" CRLF,
-                                    r->headers_out.content_type);
+#if 0
+    if (r->headers_out.content_type.len) {
+        ngx_memcpy(h->last.mem, "Content-Type: ", 14);
+        h->last.mem += 14;
+        ngx_memcpy(h->last.mem, r->headers_out.content_type.data,
+                   r->headers_out.content_type.len);
+        h->last.mem += r->headers_out.content_type.len;
+        *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+    }
+#endif
 
-    ngx_memcpy(h->last.mem, "Server: ", 8);
-    h->last.mem += 8;
-    if (r->headers_out.server) {
-        h->last.mem = ngx_cpystrn(h->last.mem, r->headers_out.server,
-                                  h->end - h->last.mem);
-        /* check space */
+    if (r->keepalive) {
+        ngx_memcpy(h->last.mem, "Connection: keep-alive" CRLF, 24);
+        h->last.mem += 24;
 
     } else {
-        ngx_memcpy(h->last.mem, NGINX_VER, sizeof(NGINX_VER) - 1);
-        h->last.mem += sizeof(NGINX_VER) - 1;
+        ngx_memcpy(h->last.mem, "Connection: close" CRLF, 19);
+        h->last.mem += 19;
     }
-    *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+
+    for (i = 0; i < r->headers_out.headers->nelts; i++) {
+        if (header[i].key.len == 0)
+            continue;
+
+        ngx_memcpy(h->last.mem, header[i].key.data, header[i].key.len);
+        h->last.mem += header[i].key.len;
+        *(h->last.mem++) = ':' ; *(h->last.mem++) = ' ' ;
+
+        ngx_memcpy(h->last.mem, header[i].value.data, header[i].value.len);
+        h->last.mem += header[i].value.len;
+        *(h->last.mem++) = CR; *(h->last.mem++) = LF;
+    }
 
     /* end of HTTP header */
     *(h->last.mem++) = CR; *(h->last.mem++) = LF;
 
-    ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)),
-                  /* STUB */
-                  -1);
-/*
-                  NGX_HTTP_FILTER_ERROR);
-*/
+    ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)), NGX_ERROR);
 
     ch->hunk = h;
     ch->next = NULL;
--- a/src/http/ngx_http_modules.c
+++ b/src/http/ngx_http_modules.c
@@ -9,7 +9,9 @@ extern ngx_http_module_t ngx_http_index_
 ngx_http_module_t *ngx_http_modules[] = {
     &ngx_http_write_filter_module,
     &ngx_http_output_filter_module,
+
+    &ngx_http_index_module,
     &ngx_http_core_module,
-    &ngx_http_index_module,
+
     NULL
 };
--- a/src/http/ngx_http_output_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -20,10 +20,14 @@ static ngx_command_t ngx_http_output_fil
 
 ngx_http_module_t  ngx_http_output_filter_module = {
     NGX_HTTP_MODULE,
+
     NULL,                                  /* create server config */
     ngx_http_output_filter_create_conf,    /* create location config */
     ngx_http_output_filter_commands,       /* module directives */
+
     NULL,                                  /* init module */
+    NULL,                                  /* translate handler */
+
     ngx_http_output_filter_init            /* init output body filter */
 };
 
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -312,7 +312,7 @@ printf("\nstate: %d, pos: %x, end: %x, c
     }
 }
 
-int ngx_read_http_header_line(ngx_http_request_t *r)
+int ngx_read_http_header_line(ngx_http_request_t *r, ngx_hunk_t *h)
 {
     char   c, ch;
     char  *p;
@@ -329,14 +329,14 @@ int ngx_read_http_header_line(ngx_http_r
     } state;
 
     state = r->state;
-    p = r->header_in->pos.mem;
+    p = h->pos.mem;
 
-    while (p < r->header_in->last.mem && state < sw_done) {
+    while (p < h->last.mem && state < sw_done) {
         ch = *p++;
 
 /*
 printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s",
-       state, p, r->header_in->last.mem, ch, p);
+       state, p, h->last.mem, ch, p);
 */
 
         switch (state) {
@@ -470,7 +470,7 @@ printf("\nstate: %d, pos: %x, end: %x, c
         }
     }
 
-    r->header_in->pos.mem = p;
+    h->pos.mem = p;
 
     if (state == sw_done) {
         r->state = sw_start;
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_parse_time.c
@@ -0,0 +1,64 @@
+
+time_t ngx_http_parse_time()
+{
+    enum {
+        sw_start = 0,
+    } state;
+
+    state = sw_start;
+
+    while () {
+        switch (state) {
+
+        case sw_start:
+            if (ch == ' ') {
+                ansi = 1;
+                state = sw_month;
+
+            } else if (ch == ',')
+                state = sw_day_first_digit;
+
+            break;
+
+        case sw_day_first_digit:
+            if (ch == ' ')
+                break;
+
+            if (ch >= '0' && ch <= '9') {
+                day = ch - '0';
+                state = sw_day;
+                break;
+
+            }
+
+            return NGX_ERROR;
+
+        case sw_day:
+            if (ansi && ch == ' ') {
+                state = sw_hour_first_digit;
+                break;
+            }
+
+            if (ch >= '0' && ch <= '9') {
+                day = ch - '0';
+                state = ansi ? sw_space_before_hour : sw_before_month;
+                break;
+            }
+
+            return NGX_ERROR;
+
+        case sw_before_month:
+            if (ch == ' ') {
+                rfc822 = 1;
+            }
+
+            if (ch == '-') {
+                rfc850 = 1;
+            }
+
+        case sw_space_before_hour:
+
+
+        }
+    }
+}
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_special_response.c
@@ -0,0 +1,21 @@
+
+
+#include <ngx_config.h>
+#if 0
+#include <ngx_core.h>
+#endif
+#include <ngx_http.h>
+
+
+int ngx_http_special_response(ngx_http_request_t *r, int error)
+{
+    switch (error) {
+
+    default:
+        r->headers_out.status = error;
+        return ngx_http_header_filter(r);
+
+    }
+
+    return ngx_http_error(r, error);
+}
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -15,10 +15,14 @@ static void *ngx_http_write_filter_creat
 
 ngx_http_module_t  ngx_http_write_filter_module = {
     NGX_HTTP_MODULE,
+
     NULL,                                  /* create server config */
     ngx_http_write_filter_create_conf,     /* create location config */
     ngx_http_write_filter_commands,        /* module directives */
+
     NULL,                                  /* init module */
+    NULL,                                  /* translate handler */
+
     NULL                                   /* init output body filter */
 };
 
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -12,6 +12,9 @@ typedef struct stat              ngx_fil
 #define ngx_open_file            open
 #define ngx_open_file_n          "open()"
 
+#define ngx_close_file           close
+#define ngx_close_file_n         "close()"
+
 #define ngx_read_file_n          "read()"
 
 #define NGX_FILE_RDONLY          O_RDONLY