changeset 143:5526213be452

nginx-0.0.1-2003-10-10-19:10:50 import
author Igor Sysoev <igor@sysoev.ru>
date Fri, 10 Oct 2003 15:10:50 +0000
parents cb77c084acdb
children ef8c87afcfc5
files src/core/ngx_connection.h src/core/ngx_core.h src/event/ngx_event.h src/event/ngx_event_proxy.c src/event/ngx_event_proxy.h src/http/modules/ngx_http_static_handler.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/ngx_http.c src/http/ngx_http.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_header_filter.c src/http/ngx_http_output_filter.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_special_response.c src/http/ngx_http_write_filter.c src/os/unix/ngx_freebsd_init.c src/os/unix/ngx_freebsd_init.h src/os/unix/ngx_freebsd_sendfile_chain.c
diffstat 20 files changed, 394 insertions(+), 321 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -102,7 +102,6 @@ struct ngx_connection_s {
     unsigned          pipeline:1;
     unsigned          unexpected_eof:1;
     unsigned          tcp_nopush:1;
-    unsigned          tcp_nopush_enabled:1;
 #if (HAVE_IOCP)
     unsigned          accept_context_updated:1;
 #endif
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -36,12 +36,12 @@ typedef struct ngx_connection_s  ngx_con
 #define  NGX_OK          0
 #define  NGX_ERROR      -1
 #define  NGX_AGAIN      -2
+#define  NGX_DECLINED   -4
+#define  NGX_ABORT      -5
+
+/*
 #define  NGX_DONE       -3
-/*
 #define  NGX_BUSY       -3
-*/
-#define  NGX_DECLINED   -4
-/*
 #define  NGX_ALERT      -5
 */
 
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -379,6 +379,106 @@ void ngx_worker(ngx_cycle_t *cycle);
 #include <ngx_iocp_module.h>
 #endif
 
+
+
+ngx_inline static int ngx_handle_read_event(ngx_event_t *rev)
+{
+    if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
+
+        /* aio, iocp, epoll */
+
+        return NGX_OK;
+    }
+
+    if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
+
+        /* kqueue */
+
+        if (!rev->active && !rev->ready) {
+            if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT)
+                                                                == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+        }
+
+        return NGX_OK;
+    }
+
+    /* select, poll, /dev/poll */
+
+    if (!rev->active && !rev->ready) {
+        if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        return NGX_OK;
+    }
+
+    if (rev->active && rev->ready) {
+        if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        return NGX_OK;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_inline static int ngx_handle_write_event(ngx_event_t *wev, int lowat)
+{
+    if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
+
+        /* aio, iocp, epoll */
+
+        return NGX_OK;
+    }
+
+    if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
+
+        /* kqueue */
+
+#if (HAVE_LOWAT_EVENT) /* kqueue's NOTE_LOWAT */
+
+        if (ngx_event_flags & NGX_HAVE_LOWAT_EVENT) {
+            wev->lowat = lowat;
+        }
+
+#endif
+        if (!wev->active && !wev->ready) {
+            if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT)
+                                                                == NGX_ERROR) {
+                return NGX_ERROR;
+            }
+        }
+
+        return NGX_OK;
+    }
+
+    /* select, poll, /dev/poll */
+
+    if (!wev->active && !wev->ready) {
+        if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        return NGX_OK;
+    }
+
+    if (wev->active && wev->ready) {
+        if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+
+        return NGX_OK;
+    }
+
+    return NGX_OK;
+}
+
+
+
 /* ***************************** */
 
 
--- a/src/event/ngx_event_proxy.c
+++ b/src/event/ngx_event_proxy.c
@@ -82,16 +82,14 @@ ngx_log_debug(p->log, "free hunk: %08X:%
             } else if (p->allocated < p->max_block_size) {
                 h = ngx_create_temp_hunk(p->pool, p->block_size, 20, 20);
                 if (h == NULL) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
 
                 p->allocated += p->block_size;
 
                 temp = ngx_alloc_chain_entry(p->pool);
                 if (temp == NULL) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
 
                 temp->hunk = h;
@@ -163,8 +161,7 @@ ngx_log_debug(p->log, "recv_chain: %d" _
             if (p->upstream->read->blocked) {
                 if (ngx_add_event(p->upstream->read, NGX_READ_EVENT,
                                                NGX_LEVEL_EVENT) == NGX_ERROR) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
                 p->block_upstream = 0;
                 p->upstream->read->blocked = 0;
@@ -237,8 +234,7 @@ ngx_log_debug(p->log, "recv_chain: %d" _
 
                 h = ngx_alloc_hunk(p->pool);
                 if (h == NULL) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
 
                 ngx_memcpy(h, entry->hunk, sizeof(ngx_hunk_t));
@@ -248,8 +244,7 @@ ngx_log_debug(p->log, "recv_chain: %d" _
 
                 temp = ngx_alloc_chain_entry(p->pool);
                 if (temp == NULL) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
 
                 temp->hunk = h;
@@ -282,8 +277,7 @@ ngx_log_debug(p->log, "recv_chain: %d" _
 
         if (p->input_filter) {
             if (p->input_filter(p, chain) == NGX_ERROR) {
-                p->fatal_error = 1;
-                return NGX_ERROR;
+                return NGX_ABORT;
             }
         }
 
@@ -326,14 +320,12 @@ ngx_log_debug(p->log, "eof: %d block: %d
 #if (NGX_EVENT_COPY_FILTER)
 
             if (p->input_filter(p, NULL) == NGX_ERROR) {
-                p->fatal_error = 1;
-                return NGX_ERROR;
+                return NGX_ABORT;
             }
 #else
             if (p->input_filter) {
                 if (p->input_filter(p, NULL) == NGX_ERROR) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
 
             } else {
@@ -380,18 +372,14 @@ ngx_log_debug(p->log, "eof: %d block: %d
         }
 
         if (p->out_hunks && p->downstream->write->ready) {
-            if (ngx_event_proxy_write_to_downstream(p) == NGX_ERROR
-                && p->fatal_error)
-            {
-                return NGX_ERROR;
+            if (ngx_event_proxy_write_to_downstream(p) == NGX_ABORT) {
+                return NGX_ABORT;
             }
         }
 
     } else if ((p->out_hunks || p->in_hunks) && p->downstream->write->ready) {
-        if (ngx_event_proxy_write_to_downstream(p) == NGX_ERROR
-            && p->fatal_error)
-        {
-            return NGX_ERROR;
+        if (ngx_event_proxy_write_to_downstream(p) == NGX_ABORT) {
+            return NGX_ABORT;
         }
     }
 
@@ -404,8 +392,7 @@ ngx_log_debug(p->log, "upstream level: %
         && ngx_event_flags & NGX_USE_LEVEL_EVENT)
     {
         if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) == NGX_ERROR) {
-            p->fatal_error = 1;
-            return NGX_ERROR;
+            return NGX_ABORT;
         }
 
         p->upstream->read->blocked = 1;
@@ -437,8 +424,7 @@ int ngx_event_proxy_write_to_downstream(
     {
         if (ngx_del_event(p->downstream->write, NGX_WRITE_EVENT, 0)
                                                                 == NGX_ERROR) {
-            p->fatal_error = 1;
-            return NGX_ERROR;
+            return NGX_ABORT;
         }
 
         p->downstream->write->blocked = 1;
@@ -516,8 +502,7 @@ ngx_log_debug(p->log, "event proxy: %d" 
             if (p->downstream->write->blocked) {
                 if (ngx_add_event(p->downstream->write, NGX_WRITE_EVENT,
                                                NGX_LEVEL_EVENT) == NGX_ERROR) {
-                    p->fatal_error = 1;
-                    return NGX_ERROR;
+                    return NGX_ABORT;
                 }
                 p->downstream->write->blocked = 0;
             }
@@ -584,8 +569,8 @@ ngx_log_debug(p->log, "event proxy: %d" 
     }
 
     if (p->upstream->read->ready) {
-        if (ngx_event_proxy_read_upstream(p) == NGX_ERROR && p->fatal_error) {
-            return NGX_ERROR;
+        if (ngx_event_proxy_read_upstream(p) == NGX_ERROR) {
+            return NGX_ABORT;
         }
     }
 
@@ -610,8 +595,7 @@ ngx_log_debug(p->log, "write to file");
                                   p->cachable);
 
         if (rc == NGX_ERROR) {
-            p->fatal_error = 1;
-            return NGX_ERROR;
+            return NGX_ABORT;
         }
 
         if (rc == NGX_AGAIN) {
@@ -660,8 +644,7 @@ ngx_log_debug(p->log, "write to file");
 
     if (ngx_write_chain_to_file(p->temp_file, p->in_hunks, p->temp_offset,
                                 p->pool) == NGX_ERROR) {
-        p->fatal_error = 1;
-        return NGX_ERROR;
+        return NGX_ABORT;
     }
 
     for (entry = p->in_hunks; entry; entry = next) {
--- a/src/event/ngx_event_proxy.h
+++ b/src/event/ngx_event_proxy.h
@@ -40,7 +40,6 @@ struct ngx_event_proxy_s {
     void              *output_data;
 
     unsigned           cachable:1;
-    unsigned           fatal_error:1;
     unsigned           block_upstream:1;
     unsigned           upstream_eof:1;
     unsigned           upstream_error:1;
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -127,33 +127,12 @@ int ngx_http_static_handler(ngx_http_req
 
 
     rc = ngx_http_send_header(r);
-    if (rc == NGX_ERROR || rc > NGX_OK) {
-        ngx_http_finalize_request(r, rc);
-        return NGX_OK;
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
     }
 
-    if (r->header_only) {
-        ngx_http_finalize_request(r, rc);
-
-#if 0
-        if (rc == NGX_AGAIN) {
-            ngx_http_set_write_handler(r);
-
-        } else {
-            ngx_http_finalize_request(r, 0);
-        }
-#endif
-
-        return NGX_OK;
-    }
-
-
-#if 0
     h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
-#else
-    h->type = NGX_HUNK_FILE;
-#endif
-
 
     h->file_pos = 0;
     h->file_last = ngx_file_size(r->file.info);
@@ -161,20 +140,5 @@ int ngx_http_static_handler(ngx_http_req
     h->file->fd = r->file.fd;
     h->file->log = r->connection->log;
 
-    rc = ngx_http_output_filter(r, h);
-
-    ngx_http_finalize_request(r, rc);
-
-#if 0
-    if (r->main == NULL) {
-        if (rc == NGX_AGAIN) {
-            ngx_http_set_write_handler(r);
-
-        } else {
-            ngx_http_finalize_request(r, 0);
-        }
-    }
-#endif
-
-    return NGX_OK;
+    return ngx_http_output_filter(r, h);
 }
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -1108,7 +1108,9 @@ static int ngx_http_proxy_init(ngx_cycle
     ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
     cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
 
-    ngx_test_null(h, ngx_push_array(&cmcf->translate_handlers), NGX_ERROR);
+    ngx_test_null(h, ngx_push_array(
+                             &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
+                  NGX_ERROR);
 
     *h = ngx_http_proxy_translate_handler;
 
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -203,8 +203,21 @@ static char *ngx_http_block(ngx_conf_t *
 
     /* init list of the handlers */
 
-    ngx_init_array(cmcf->translate_handlers, cf->cycle->pool,
-                   10, sizeof(ngx_http_handler_pt), NGX_CONF_ERROR);
+    ngx_init_array(cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
+                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+
+    cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK;
+    cmcf->phases[NGX_HTTP_REWRITE_PHASE].post_handler =
+                                                 ngx_http_find_location_config;
+
+
+    ngx_init_array(cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers,
+                   cf->cycle->pool, 10, sizeof(ngx_http_handler_pt),
+                   NGX_CONF_ERROR);
+
+    cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].type = NGX_OK;
+
 
     ngx_init_array(cmcf->index_handlers, cf->cycle->pool,
                    3, sizeof(ngx_http_handler_pt), NGX_CONF_ERROR);
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -17,8 +17,6 @@ typedef struct {
 } ngx_http_log_ctx_t;
 
 
-typedef int (*ngx_http_handler_pt)(ngx_http_request_t *r);
-
 typedef int (*ngx_http_output_header_filter_p)(ngx_http_request_t *r);
 
 typedef int (*ngx_http_output_body_filter_p)
@@ -51,7 +49,7 @@ int ngx_http_parse_header_line(ngx_http_
 int ngx_http_find_server_conf(ngx_http_request_t *r);
 void ngx_http_handler(ngx_http_request_t *r);
 void ngx_http_finalize_request(ngx_http_request_t *r, int error);
-void ngx_http_set_write_handler(ngx_http_request_t *r);
+void ngx_http_writer(ngx_event_t *wev);
 
 
 int ngx_http_send_last(ngx_http_request_t *r);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1,6 +1,7 @@
 
 #include <ngx_config.h>
 #include <ngx_core.h>
+#include <ngx_event.h>
 #include <ngx_http.h>
 #include <nginx.h>
 
@@ -8,6 +9,8 @@
 /* STUB */
 int ngx_http_static_handler(ngx_http_request_t *r);
 
+static void ngx_http_phase_event_handler(ngx_event_t *rev);
+static void ngx_http_run_phases(ngx_http_request_t *r);
 
 static int ngx_http_core_index_handler(ngx_http_request_t *r);
 
@@ -201,12 +204,7 @@ ngx_module_t  ngx_http_core_module = {
 
 void ngx_http_handler(ngx_http_request_t *r)
 {
-    int                         rc, i;
-    ngx_http_log_ctx_t         *lcx;
-    ngx_http_handler_pt        *h;
-    ngx_http_core_loc_conf_t   *clcf, **clcfp;
-    ngx_http_core_srv_conf_t   *cscf;
-    ngx_http_core_main_conf_t  *cmcf;
+    ngx_http_log_ctx_t  *lcx;
 
     r->connection->unexpected_eof = 0;
 
@@ -221,11 +219,100 @@ void ngx_http_handler(ngx_http_request_t
 
     /* TEST STUB */ r->lingering_close = 1;
 
+    r->connection->write->event_handler = ngx_http_phase_event_handler;
 
-    /* TODO: run rewrite url phase */
+    r->phase = 0;
+    r->phase_handler = 0;
+
+    ngx_http_run_phases(r);
+
+    return;
+}
+
+
+static void ngx_http_phase_event_handler(ngx_event_t *ev)
+{
+    ngx_connection_t    *c;
+    ngx_http_request_t  *r;
+
+    c = ev->data;
+    r = c->data;
+
+    ngx_http_run_phases(r);
+
+    return;
+}
 
 
-    /* find location config */
+static void ngx_http_run_phases(ngx_http_request_t *r)
+{
+    int                         rc;
+    ngx_http_handler_pt        *h;
+    ngx_http_core_main_conf_t  *cmcf;
+
+    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+    rc = NGX_DECLINED;
+
+    for (/* void */; r->phase < NGX_HTTP_LAST_PHASE; r->phase++) {
+
+        h = cmcf->phases[r->phase].handlers.elts;
+        for (r->phase_handler = cmcf->phases[r->phase].handlers.nelts - 1;
+             r->phase_handler >= 0;
+             r->phase_handler--)
+        {
+            rc = h[r->phase_handler](r);
+
+            if (rc == NGX_DECLINED) {
+                continue;
+            }
+
+            if (rc == NGX_AGAIN) {
+                return;
+            }
+
+            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+                ngx_http_finalize_request(r, rc);
+                return;
+            }
+
+            if (rc == NGX_OK && cmcf->phases[r->phase].type == NGX_OK) {
+                break;
+            }
+        }
+
+        if (cmcf->phases[r->phase].post_handler) {
+            rc = cmcf->phases[r->phase].post_handler(r);
+
+            if (rc == NGX_AGAIN) {
+                return;
+            }
+
+            if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+                ngx_http_finalize_request(r, rc);
+                return;
+            }
+        }
+    }
+
+    if (r->content_handler) {
+        r->connection->write->event_handler = ngx_http_writer;
+        rc = r->content_handler(r);
+        ngx_http_finalize_request(r, rc);
+        return;
+    }
+
+    /* TODO: no handlers found ? */
+    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    return;
+}
+
+
+int ngx_http_find_location_config(ngx_http_request_t *r)
+{
+    int                        i, rc;
+    ngx_http_core_loc_conf_t  *clcf, **clcfp;
+    ngx_http_core_srv_conf_t  *cscf;
 
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
@@ -261,36 +348,7 @@ ngx_log_debug(r->connection->log, "rc: %
         r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
     }
 
-    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
-
-    /* run translation phase */
-
-    h = cmcf->translate_handlers.elts;
-    for (i = cmcf->translate_handlers.nelts - 1; i >= 0; i--) {
-
-        rc = h[i](r);
-
-        if (rc == NGX_DECLINED) {
-            continue;
-        }
-
-        if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-            ngx_http_finalize_request(r, rc);
-            return;
-        }
-
-        if (rc == NGX_OK) {
-            rc = r->handler(r);
-            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-                ngx_http_finalize_request(r, rc);
-            }
-            return;
-        }
-    }
-
-    /* TODO: no handlers found ? */
-    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-    return;
+    return NGX_OK;
 }
 
 
@@ -305,14 +363,14 @@ int ngx_http_core_translate_handler(ngx_
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     if (clcf->handler) {
-        r->handler = clcf->handler;
+        r->content_handler = clcf->handler;
         return NGX_OK;
     }
 
     cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
     if (r->uri.data[r->uri.len - 1] == '/') {
-        r->handler = ngx_http_core_index_handler;
+        r->content_handler = ngx_http_core_index_handler;
         return NGX_OK;
     }
 
@@ -424,7 +482,7 @@ ngx_log_debug(r->connection->log, "HTTP 
         return NGX_HTTP_MOVED_PERMANENTLY;
     }
 
-    r->handler = ngx_http_static_handler;
+    r->content_handler = ngx_http_static_handler;
 
     return NGX_OK;
 }
@@ -548,7 +606,9 @@ static int ngx_http_core_init(ngx_cycle_
     ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
     cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
 
-    ngx_test_null(h, ngx_push_array(&cmcf->translate_handlers), NGX_ERROR);
+    ngx_test_null(h, ngx_push_array(
+                             &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
+                  NGX_ERROR);
 
     *h = ngx_http_core_translate_handler;
 
@@ -756,7 +816,7 @@ static void *ngx_http_core_create_main_c
     ngx_http_core_main_conf_t *cmcf;
 
     ngx_test_null(cmcf,
-                  ngx_palloc(cf->pool, sizeof(ngx_http_core_main_conf_t)),
+                  ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)),
                   NGX_CONF_ERROR);
 
     ngx_init_array(cmcf->servers, cf->pool,
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -18,9 +18,20 @@ typedef struct {
 
 
 typedef struct {
-    ngx_array_t  servers;              /* array of ngx_http_core_srv_conf_t */
-    ngx_array_t  translate_handlers;
-    ngx_array_t  index_handlers;
+    ngx_array_t          handlers;
+    int                  type;                /* NGX_OK, NGX_DECLINED */
+    ngx_http_handler_pt  post_handler;
+} ngx_http_phase_t;
+
+#define NGX_HTTP_REWRITE_PHASE    0
+#define NGX_HTTP_TRANSLATE_PHASE  1
+#define NGX_HTTP_LAST_PHASE       2
+
+typedef struct {
+    ngx_array_t       servers;         /* array of ngx_http_core_srv_conf_t */
+
+    ngx_http_phase_t  phases[NGX_HTTP_LAST_PHASE];
+    ngx_array_t       index_handlers;
 } ngx_http_core_main_conf_t;
 
 
@@ -138,6 +149,7 @@ extern int ngx_http_max_module;
 
 
 
+int ngx_http_find_location_config(ngx_http_request_t *r);
 int ngx_http_core_translate_handler(ngx_http_request_t *r);
 
 int ngx_http_internal_redirect(ngx_http_request_t *r,
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -4,12 +4,6 @@
 #include <ngx_http.h>
 #include <nginx.h>
 
-/* STUB probably, needed for ngx_freebsd_tcp_nopush_flush */
-#ifdef __FreeBSD__
-#include <ngx_freebsd_init.h>
-#endif
-
-
 
 static int ngx_http_header_filter_init(ngx_cycle_t *cycle);
 static int ngx_http_header_filter(ngx_http_request_t *r);
@@ -100,23 +94,6 @@ static int ngx_http_header_filter(ngx_ht
     ngx_chain_t       *ch;
     ngx_table_elt_t   *header;
 
-#ifdef __FreeBSD__
-
-    if (r->keepalive) {
-        if (ngx_freebsd_tcp_nopush_flush) {
-            r->connection->tcp_nopush_enabled = 1;
-        }
-
-    } else {
-        r->connection->tcp_nopush_enabled = 1;
-    }
-
-#else
-
-    r->connection->tcp_nopush_enabled = 1;
-
-#endif
-
     if (r->http_version < NGX_HTTP_VERSION_10) {
         return NGX_OK;
     }
--- a/src/http/ngx_http_output_filter.c
+++ b/src/http/ngx_http_output_filter.c
@@ -203,7 +203,9 @@ int ngx_http_output_filter(ngx_http_requ
             ctx->last_out = &ce->next;
             ctx->hunk = NULL;
 
-            break;
+            if (ctx->free == NULL) {
+                break;
+            }
         }
 
         if (ctx->out == NULL && last != NGX_NONE) {
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -10,7 +10,7 @@ static void ngx_http_process_request_lin
 static void ngx_http_process_request_headers(ngx_event_t *rev);
 static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
 
-static void ngx_http_writer(ngx_event_t *ev);
+static void ngx_http_set_write_handler(ngx_http_request_t *r);
 
 static void ngx_http_block_read(ngx_event_t *ev);
 static void ngx_http_read_discarded_body_event(ngx_event_t *rev);
@@ -112,6 +112,13 @@ void ngx_http_init_connection(ngx_connec
         return;
     }
 
+    if (ngx_handle_read_event(rev) == NGX_ERROR) {
+        ngx_http_close_connection(c);
+        return;
+    }
+
+#if 0
+
     if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
         /* kqueue */
         event = NGX_CLEAR_EVENT;
@@ -124,6 +131,10 @@ void ngx_http_init_connection(ngx_connec
     if (ngx_add_event(rev, NGX_READ_EVENT, event) == NGX_ERROR) {
         ngx_http_close_connection(c);
     }
+
+#endif
+
+    return;
 }
 
 
@@ -660,6 +671,7 @@ static void ngx_http_process_request_hea
             }
 
             rev->event_handler = ngx_http_block_read;
+            c->write->event_handler = ngx_http_writer;
             ngx_http_handler(r);
             return;
 
@@ -743,6 +755,13 @@ static ssize_t ngx_http_read_request_hea
             r->header_timeout_set = 1;
         }
 
+        if (ngx_handle_read_event(rev) == NGX_ERROR) {
+            ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            ngx_http_close_connection(r->connection);
+            return NGX_ERROR;
+        }
+
+#if 0
         if (!rev->active) {
             if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
                 /* kqueue */
@@ -759,6 +778,7 @@ static ssize_t ngx_http_read_request_hea
                 return NGX_ERROR;
             }
         }
+#endif
 
         return NGX_AGAIN;
     }
@@ -780,17 +800,14 @@ static ssize_t ngx_http_read_request_hea
 }
 
 
-void ngx_http_finalize_request(ngx_http_request_t *r, int error)
+void ngx_http_finalize_request(ngx_http_request_t *r, int rc)
 {
-    int           rc;
     ngx_event_t  *rev, *wev;
 
-    if (r->main) {
+    if (r->main || r->closed) {
         return;
     }
 
-    rc = error;
-
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
 
         rev = r->connection->read;
@@ -805,37 +822,18 @@ void ngx_http_finalize_request(ngx_http_
             wev->timer_set = 0;
         }
 
-        rc = ngx_http_special_response_handler(r, rc);
-
-        if (rc == NGX_AGAIN) {
-            return;
-        }
+        ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
 
-        if (rc == NGX_ERROR) {
-            ngx_http_close_request(r, 0);
-            ngx_http_close_connection(r->connection);
-            return;
-        }
-
-#if 1
         return;
-#endif
 
     } else if (rc == NGX_ERROR) {
-        r->keepalive = 0;
-        r->lingering_close = 0;
+        ngx_http_close_request(r, 0);
+        ngx_http_close_connection(r->connection);
+        return;
 
-    } else {
-        if (ngx_http_send_last(r) == NGX_ERROR) {
-            ngx_http_close_request(r, 0);
-            ngx_http_close_connection(r->connection);
-            return;
-        }
-
-        if (rc == NGX_AGAIN) {
-            ngx_http_set_write_handler(r);
-            return;
-        }
+    } else if (rc == NGX_AGAIN) {
+        ngx_http_set_write_handler(r);
+        return;
     }
 
     rev = r->connection->read;
@@ -865,7 +863,7 @@ void ngx_http_finalize_request(ngx_http_
 }
 
 
-void ngx_http_set_write_handler(ngx_http_request_t *r)
+static void ngx_http_set_write_handler(ngx_http_request_t *r)
 {
     int                        event;
     ngx_event_t               *wev;
@@ -883,6 +881,13 @@ void ngx_http_set_write_handler(ngx_http
     ngx_add_timer(wev, clcf->send_timeout);
     wev->timer_set = 1;
 
+    if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) {
+        ngx_http_close_request(r, 0);
+        ngx_http_close_connection(r->connection);
+    }
+
+#if 0
+
     if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
         /* aio, iocp, epoll */
         return;
@@ -910,11 +915,13 @@ void ngx_http_set_write_handler(ngx_http
         ngx_http_close_connection(r->connection);
     }
 
+#endif
+
     return;
 }
 
 
-static void ngx_http_writer(ngx_event_t *wev)
+void ngx_http_writer(ngx_event_t *wev)
 {
     int                        rc;
     ngx_event_t               *rev;
@@ -1454,6 +1461,10 @@ void ngx_http_close_request(ngx_http_req
     ctx->url = NULL;
 
     ngx_destroy_pool(r->pool);
+
+    r->closed = 1;
+
+    return;
 }
 
 
@@ -1497,6 +1508,8 @@ void ngx_http_close_connection(ngx_conne
     c->fd = -1;
 
     ngx_destroy_pool(c->pool);
+
+    return;
 }
 
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -126,6 +126,8 @@ typedef struct {
 
 typedef struct ngx_http_request_s ngx_http_request_t;
 
+typedef int (*ngx_http_handler_pt)(ngx_http_request_t *r);
+
 struct ngx_http_request_s {
     ngx_connection_t    *connection;
 
@@ -143,8 +145,6 @@ struct ngx_http_request_s {
     ngx_http_headers_in_t     headers_in;
     ngx_http_headers_out_t    headers_out;
 
-    int  (*handler)(ngx_http_request_t *r);
-
     time_t               lingering_time;
 
     int                  method;
@@ -166,6 +166,9 @@ struct ngx_http_request_s {
     ngx_str_t           *server_name;
     ngx_array_t         *virtual_names;
 
+    int                  phase;
+    int                  phase_handler;
+    ngx_http_handler_pt  content_handler;
 
     char                *discarded_buffer;
 
@@ -188,6 +191,7 @@ struct ngx_http_request_s {
     unsigned             header_only:1;
     unsigned             keepalive:1;
     unsigned             lingering_close:1;
+    unsigned             closed:1;
 
     /* TODO: use filter or bits ???? */
     int                  filter;
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -200,20 +200,8 @@ int ngx_http_special_response_handler(ng
 
     rc = ngx_http_send_header(r);
 
-    if (rc == NGX_ERROR) {
-        return NGX_ERROR;
-    }
-
-    if (r->header_only) {
-        ngx_http_finalize_request(r, rc);
-#if 0
-        if (rc == NGX_AGAIN) {
-            ngx_http_set_write_handler(r);
-            return NGX_AGAIN;
-        }
-#endif
-
-        return NGX_OK;
+    if (rc == NGX_ERROR || r->header_only) {
+        return rc;
     }
 
     if (error_pages[err].len == 0) {
@@ -236,7 +224,7 @@ int ngx_http_special_response_handler(ng
     h->pos = error_tail;
     h->last = error_tail + sizeof(error_tail) - 1;
 
-    if (1) {
+    if (/* STUB: "msie_padding on/off" */ 1) {
         if (ngx_http_output_filter(r, h) == NGX_ERROR) {
             return NGX_ERROR;
         }
@@ -250,19 +238,5 @@ int ngx_http_special_response_handler(ng
 
     h->type |= NGX_HUNK_LAST;
 
-    rc = ngx_http_output_filter(r, h);
-
-    ngx_http_finalize_request(r, rc);
-
-#if 0
-    if (r->main == NULL) {
-        if (rc == NGX_AGAIN) {
-            ngx_http_set_write_handler(r);
-            return NGX_AGAIN;
-        }
-    }
-#endif
-
-    return NGX_OK;
-
+    return ngx_http_output_filter(r, h);
 }
--- a/src/http/ngx_http_write_filter.c
+++ b/src/http/ngx_http_write_filter.c
@@ -143,6 +143,10 @@ int ngx_http_write_filter(ngx_http_reque
         return NGX_AGAIN;
     }
 
+    if (size == 0) {
+        return NGX_OK;
+    }
+
     chain = ngx_write_chain(r->connection, ctx->out);
 
 #if (NGX_DEBUG_WRITE_FILTER)
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -9,7 +9,7 @@ int ngx_freebsd_kern_osreldate;
 int ngx_freebsd_hw_ncpu;
 int ngx_freebsd_net_inet_tcp_sendspace;
 int ngx_freebsd_sendfile_nbytes_bug;
-int ngx_freebsd_tcp_nopush_flush;
+int ngx_freebsd_use_tcp_nopush;
 
 /* FreeBSD 5.0 */
 int ngx_freebsd_kern_ipc_zero_copy_send;
@@ -125,7 +125,7 @@ int ngx_os_init(ngx_log_t *log)
 
 
     if ((version < 500000 && version >= 440003) || version >= 500017) {
-        ngx_freebsd_tcp_nopush_flush = 1;
+        ngx_freebsd_use_tcp_nopush = 1;
     }
 
 
--- a/src/os/unix/ngx_freebsd_init.h
+++ b/src/os/unix/ngx_freebsd_init.h
@@ -19,9 +19,8 @@ extern int ngx_freebsd_kern_osreldate;
 extern int ngx_freebsd_hw_ncpu;
 extern int ngx_freebsd_net_inet_tcp_sendspace;
 extern int ngx_freebsd_sendfile_nbytes_bug;
-extern int ngx_freebsd_tcp_nopush_flush;
 extern int ngx_freebsd_kern_ipc_zero_copy_send;
-extern int ngx_freebsd_tcp_nopush_flush;
+extern int ngx_freebsd_use_tcp_nopush;
 
 
 #endif /* _NGX_FREEBSD_INIT_H_INCLUDED_ */
--- a/src/os/unix/ngx_freebsd_sendfile_chain.c
+++ b/src/os/unix/ngx_freebsd_sendfile_chain.c
@@ -14,16 +14,16 @@
  * and the first part of the file in one packet but also sends 4K pages
  * in the full packets.
  *
- * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not not flush
- * the pending data that less than MSS and the data sent with 5 second delay.
- * So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection
- * is not needed to be keepalive.
+ * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush
+ * the pending data that less than MSS so the data is sent with 5 second delay.
+ * We do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used
+ * for non-keepalive HTTP connections.
  */
 
 
 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in)
 {
-    int              rc, eintr, tcp_nopush;
+    int              rc, eintr;
     char            *prev;
     ssize_t          hsize, size;
     off_t            sent;
@@ -34,8 +34,6 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
     ngx_hunk_t      *file;
     ngx_chain_t     *ce, *tail;
 
-    tcp_nopush = 0;
-
     do {
         ce = in;
         file = NULL;
@@ -47,42 +45,33 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
         ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec),
                        NGX_CHAIN_ERROR);
 
-        /* create the header iovec */
+        /* create the iovec and coalesce the neighbouring chain entries */
+
+        prev = NULL;
+        iov = NULL;
 
-#if 0
-        if (ngx_hunk_in_memory_only(ce->hunk) || ngx_hunk_special(ce->hunk)) {
-#endif
-            prev = NULL;
-            iov = NULL;
+        for (ce = in; ce; ce = ce->next) {
+            if (ngx_hunk_special(ce->hunk)) {
+                continue;
+            }
 
-            /* create the iovec and coalesce the neighbouring chain entries */
-
-            for ( /* void */; ce; ce = ce->next) {
-                if (ngx_hunk_special(ce->hunk)) {
-                    continue;
-                }
+            if (!ngx_hunk_in_memory_only(ce->hunk)) {
+                break;
+            }
 
-                if (!ngx_hunk_in_memory_only(ce->hunk)) {
-                    break;
-                }
-
-                if (prev == ce->hunk->pos) {
-                    iov->iov_len += ce->hunk->last - ce->hunk->pos;
-                    prev = ce->hunk->last;
+            if (prev == ce->hunk->pos) {
+                iov->iov_len += ce->hunk->last - ce->hunk->pos;
+                prev = ce->hunk->last;
 
-                } else {
-                    ngx_test_null(iov, ngx_push_array(&header),
-                                  NGX_CHAIN_ERROR);
-                    iov->iov_base = ce->hunk->pos;
-                    iov->iov_len = ce->hunk->last - ce->hunk->pos;
-                    prev = ce->hunk->last;
-                }
+            } else {
+                ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR);
+                iov->iov_base = ce->hunk->pos;
+                iov->iov_len = ce->hunk->last - ce->hunk->pos;
+                prev = ce->hunk->last;
+            }
 
-                hsize += ce->hunk->last - ce->hunk->pos;
-            }
-#if 0
+            hsize += ce->hunk->last - ce->hunk->pos;
         }
-#endif
 
         /* TODO: coalesce the neighbouring file hunks */
 
@@ -91,57 +80,46 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(
             ce = ce->next;
         }
 
-        /* create the trailer iovec */
+        /* create the iovec and coalesce the neighbouring chain entries */
+
+        prev = NULL;
+        iov = NULL;
 
-#if 0
-        if (ce
-            && (ngx_hunk_in_memory_only(ce->hunk)
-                || ngx_hunk_special(ce->hunk)))
-        {
-#endif
-            prev = NULL;
-            iov = NULL;
-
-            /* create the iovec and coalesce the neighbouring chain entries */
-
-            for ( /* void */; ce; ce = ce->next) {
-                if (ngx_hunk_special(ce->hunk)) {
-                    continue;
-                }
+        for ( /* void */; ce; ce = ce->next) {
+            if (ngx_hunk_special(ce->hunk)) {
+                continue;
+            }
 
-                if (!ngx_hunk_in_memory_only(ce->hunk)) {
-                    break;
-                }
+            if (!ngx_hunk_in_memory_only(ce->hunk)) {
+                break;
+            }
 
-                if (prev == ce->hunk->pos) {
-                    iov->iov_len += ce->hunk->last - ce->hunk->pos;
-                    prev = ce->hunk->last;
+            if (prev == ce->hunk->pos) {
+                iov->iov_len += ce->hunk->last - ce->hunk->pos;
+                prev = ce->hunk->last;
 
-                } else {
-                    ngx_test_null(iov, ngx_push_array(&trailer),
-                                  NGX_CHAIN_ERROR);
-                    iov->iov_base = ce->hunk->pos;
-                    iov->iov_len = ce->hunk->last - ce->hunk->pos;
-                    prev = ce->hunk->last;
-                }
+            } else {
+                ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR);
+                iov->iov_base = ce->hunk->pos;
+                iov->iov_len = ce->hunk->last - ce->hunk->pos;
+                prev = ce->hunk->last;
             }
-#if 0
         }
-#endif
 
         tail = ce;
 
         if (file) {
 
-            if (!c->tcp_nopush && c->tcp_nopush_enabled) {
+            if (ngx_freebsd_use_tcp_nopush && !c->tcp_nopush) {
                 c->tcp_nopush = 1;
-                tcp_nopush = 1;
+
+ngx_log_debug(c->log, "NOPUSH");
+
                 if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
                     ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
                                   ngx_tcp_nopush_n " failed");
                     return NGX_CHAIN_ERROR;
                 }
-ngx_log_debug(c->log, "NOPUSH");
             }
 
             hdtr.headers = (struct iovec *) header.elts;
@@ -182,36 +160,28 @@ ngx_log_debug(c->log, "NOPUSH");
 #endif
 
         } else {
-            if (hsize) {
-                rc = writev(c->fd, (struct iovec *) header.elts, header.nelts);
+            rc = writev(c->fd, (struct iovec *) header.elts, header.nelts);
 
-                if (rc == -1) {
-                    err = ngx_errno;
-                    if (err == NGX_EAGAIN) {
-                        ngx_log_error(NGX_LOG_INFO, c->log, err,
-                                      "writev() EAGAIN");
+            if (rc == -1) {
+                err = ngx_errno;
+                if (err == NGX_EAGAIN) {
+                    ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN");
 
-                    } else if (err == NGX_EINTR) {
-                        eintr = 1;
-                        ngx_log_error(NGX_LOG_INFO, c->log, err,
-                                      "writev() EINTR");
+                } else if (err == NGX_EINTR) {
+                    eintr = 1;
+                    ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR");
 
-                    } else {
-                        ngx_log_error(NGX_LOG_CRIT, c->log, err,
-                                      "writev() failed");
-                        return NGX_CHAIN_ERROR;
-                    }
+                } else {
+                    ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed");
+                    return NGX_CHAIN_ERROR;
                 }
+            }
 
-                sent = rc > 0 ? rc : 0;
+            sent = rc > 0 ? rc : 0;
 
 #if (NGX_DEBUG_WRITE_CHAIN)
-                ngx_log_debug(c->log, "writev: %qd" _ sent);
+            ngx_log_debug(c->log, "writev: %qd" _ sent);
 #endif
-
-            } else {
-                sent = 0;
-            }
         }
 
         c->sent += sent;