changeset 148:5afee0074707

nginx-0.0.1-2003-10-17-00:19:16 import
author Igor Sysoev <igor@sysoev.ru>
date Thu, 16 Oct 2003 20:19:16 +0000
parents be71fca7f9d7
children 86404ba5c517
files src/core/ngx_core.h src/core/ngx_hunk.h src/core/ngx_modules.c src/event/ngx_event_connect.c src/event/ngx_event_proxy.c src/event/ngx_event_proxy.h src/http/modules/ngx_http_index_handler.c src/http/modules/ngx_http_static_handler.c src/http/modules/proxy/ngx_http_proxy_handler.c src/http/modules/proxy/ngx_http_proxy_handler.h src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_special_response.c src/os/unix/ngx_recv.c
diffstat 14 files changed, 666 insertions(+), 538 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -36,11 +36,11 @@ typedef struct ngx_connection_s  ngx_con
 #define  NGX_OK          0
 #define  NGX_ERROR      -1
 #define  NGX_AGAIN      -2
+#define  NGX_DONE       -3
 #define  NGX_DECLINED   -4
 #define  NGX_ABORT      -5
 
 /*
-#define  NGX_DONE       -3
 #define  NGX_BUSY       -3
 #define  NGX_ALERT      -5
 */
--- a/src/core/ngx_hunk.h
+++ b/src/core/ngx_hunk.h
@@ -85,9 +85,9 @@ typedef struct {
         (h->type == (h->type & (NGX_HUNK_FLUSH|NGX_HUNK_LAST)))
 
 
-#define nxg_hunk_size(h)                                                     \
-        (h->type & NGX_HUNK_IN_MEMORY) ? h->last - h->pos:                   \
-                                         (size_t) h->file_last - h->file_pos
+#define ngx_hunk_size(h)                                                     \
+        ((h->type & NGX_HUNK_IN_MEMORY) ? h->last - h->pos:                  \
+                                         (size_t) (h->file_last - h->file_pos))
 
 
 ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size,
@@ -108,14 +108,13 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_poo
 #define ngx_alloc_ce_and_set_hunk  ngx_add_hunk_to_chain
 
 
-#define ngx_chain_add_ce(ngx_chain_t *chain, ngx_chain_t **last,             \
-                         ngx_chain_t *ce)                                    \
+#define ngx_chain_add_ce(chain, last, ce)                                    \
             if (chain) {                                                     \
-                last->next = ce;                                             \
+                *last = ce;                                                  \
             } else {                                                         \
                 chain = ce;                                                  \
             }                                                                \
-            last = ce;
+            last = &ce->next
 
 
 int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **ch, ngx_chain_t *in);
--- a/src/core/ngx_modules.c
+++ b/src/core/ngx_modules.c
@@ -89,7 +89,7 @@ ngx_module_t *ngx_modules[] = {
     /* &ngx_http_ssi_filter_module, */
     &ngx_http_charset_filter_module,
 
-    /* &ngx_http_static_module, */
+    &ngx_http_static_module,
     &ngx_http_index_module,
     &ngx_http_proxy_module,
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -220,6 +220,8 @@ int ngx_event_connect_peer(ngx_peer_conn
         return NGX_AGAIN;
     }
 
+    wev->ready = 1;
+
     if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
         return NGX_ERROR;
     }
--- a/src/event/ngx_event_proxy.c
+++ b/src/event/ngx_event_proxy.c
@@ -4,21 +4,27 @@
 #include <ngx_event.h>
 #include <ngx_event_proxy.h>
 
+static int ngx_event_proxy_write_chain_to_temp_file(ngx_event_proxy_t *p);
+ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk);
+ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free,
+                                                       ngx_hunk_t *h);
+ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain,
+                                                           ngx_chain_t *ce);
+
 
 int ngx_event_proxy_read_upstream(ngx_event_proxy_t *p)
 {
     int           n, rc, size;
-    ngx_hunk_t   *h, *nh;
-    ngx_chain_t  *chain, *rest, *ce, *next;
-
-    rest = NULL;
+    ngx_hunk_t   *h;
+    ngx_chain_t  *chain, *ce, *te;
 
     p->upstream_level++;
 
-ngx_log_debug(p->log, "read upstream");
+    ngx_log_debug(p->log, "read upstream: %d" _ p->upstream->read->ready);
 
-    for ( ;; ) {
-
+    while (p->preread_hunks
+           || (p->upstream->read->ready && !p->upstream_done))
+    {
         if (p->preread_hunks) {
 
             /* use the pre-read hunks if they exist */
@@ -27,7 +33,7 @@ ngx_log_debug(p->log, "read upstream");
             p->preread_hunks = NULL;
             n = p->preread_size;
 
-ngx_log_debug(p->log, "preread: %d" _ n);
+            ngx_log_debug(p->log, "preread: %d" _ n);
 
         } else {
 
@@ -46,24 +52,14 @@ ngx_log_debug(p->log, "preread: %d" _ n)
                                   "readv() failed");
                     p->upstream_error = 1;
 
+                    break;
+
                 } else if (p->upstream->read->eof
                            && p->upstream->read->available == 0) {
                     p->upstream_eof = 1;
+
+                    break;
                 }
-
-                if ((p->upstream_eof || p->upstream_error)
-                     && p->free_raw_hunk)
-                {
-                    if (p->input_filter(p->input_data, p->free_raw_hunk->hunk)
-                                                                == NGX_ERROR) {
-                        return NGX_ABORT;
-                    }
-
-                    /* TODO: p->free_raw_hunk->next can be free()ed */
-                    p->free_raw_hunk = p->free_raw_hunk->next;
-                }
-
-                break;
             }
 #endif
 
@@ -74,23 +70,18 @@ ngx_log_debug(p->log, "preread: %d" _ n)
                 chain = p->free_raw_hunks;
                 p->free_raw_hunks = NULL;
 
-ngx_log_debug(p->log, "free hunk: %08X:%d" _ chain->hunk _
-              chain->hunk->end - chain->hunk->last);
-
             } else if (p->hunks < p->bufs.num) {
 
                 /* allocate a new hunk if it's still allowed */
 
                 ngx_test_null(h, ngx_create_temp_hunk(p->pool,
-                                                      p->bufs.size, 20, 20);
+                                                      p->bufs.size, 0, 0),
                               NGX_ABORT);
                 p->hunks++;
 
                 ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT);
                 chain = te;
 
-ngx_log_debug(p->log, "new hunk: %08X" _ chain->hunk);
-
             } else if (!p->cachable && p->downstream->write->ready) {
 
                 /*
@@ -98,7 +89,7 @@ ngx_log_debug(p->log, "new hunk: %08X" _
                  * a downstream is ready then write the hunks to a downstream.
                  */
 
-ngx_log_debug(p->log, "downstream ready");
+                ngx_log_debug(p->log, "downstream ready");
 
                 break;
 
@@ -111,7 +102,7 @@ ngx_log_debug(p->log, "downstream ready"
 
                 rc = ngx_event_proxy_write_chain_to_temp_file(p);
 
-ngx_log_debug(p->log, "temp offset: %d" _ p->temp_offset);
+                ngx_log_debug(p->log, "temp offset: %d" _ p->temp_offset);
 
                 if (rc == NGX_AGAIN) {
                     if (ngx_event_flags & NGX_USE_LEVEL_EVENT
@@ -133,21 +124,18 @@ ngx_log_debug(p->log, "temp offset: %d" 
                 chain = p->free_raw_hunks;
                 p->free_raw_hunks = NULL;
 
-ngx_log_debug(p->log, "new file hunk: %08X:%d" _ chain->hunk _
-              chain->hunk->end - chain->hunk->last);
-
             } else {
 
                 /* if there're no hunks to read in then disable a level event */
 
-ngx_log_debug(p->log, "no hunks to read in");
+                ngx_log_debug(p->log, "no hunks to read in");
     
                 break;
             }
 
             n = ngx_recv_chain(p->upstream, chain);
 
-ngx_log_debug(p->log, "recv_chain: %d" _ n);
+            ngx_log_debug(p->log, "recv_chain: %d" _ n);
 
             if (n == NGX_ERROR) {
                 p->upstream_error = 1;
@@ -159,10 +147,7 @@ ngx_log_debug(p->log, "recv_chain: %d" _
             }
 
             if (n == 0) {
-                THINK
-                if (chain->hunk->shadow == NULL) {
-                    p->free_hunks = chain;
-                }
+                p->free_raw_hunks = chain;
                 p->upstream_eof = 1;
 
                 break;
@@ -172,180 +157,41 @@ ngx_log_debug(p->log, "recv_chain: %d" _
 
         for (ce = chain; ce && n > 0; ce = ce->next) {
 
-            size = ce->hunk->end - ce->hunk->last;
-
-            if (n >= size) {
-                ce->hunk->last = ce->hunk->end;
-
-                if (p->input_filter(p->input_data, ce->hunk) == NGX_ERROR) {
-                    return NGX_ABORT;
-                }
-
-                n -= size;
-
-            } else if (p->upstream_eof || p->upstream_error) {
-
-                if (p->input_filter(p->input_data, ce->hunk) == NGX_ERROR) {
-                    return NGX_ABORT;
-                }
-
-            } else {
-                ce->hunk->last += n;
-                n = 0;
-            }
-
-
-
-
-
-
-
-
-            next = ce->next;
-            ce->next = NULL;
-
-            if (ce->hunk->shadow) {
-                for (h = ce->hunk->shadow;
-                     (h->type & NGX_HUNK_LAST_SHADOW) == 0;
-                     h = nh)
-                {
-                    nh = h->shadow;
-                    h->shadow = NULL;
-                    h->type &= ~(NGX_HUNK_TEMP
-                                 |NGX_HUNK_IN_MEMORY
-                                 |NGX_HUNK_RECYCLED);
-                }
-
-                h->shadow = NULL;
-                h->type &= ~(NGX_HUNK_TEMP
-                             |NGX_HUNK_IN_MEMORY
-                             |NGX_HUNK_RECYCLED
-                             |NGX_HUNK_LAST_SHADOW);
-                ce->hunk->shadow = NULL;
-            }
+            ngx_remove_shadow_links(ce->hunk);
 
             size = ce->hunk->end - ce->hunk->last;
 
             if (n >= size) {
                 ce->hunk->last = ce->hunk->end;
 
-                if (p->read_hunks) {
-                    p->last_read_hunk->next = ce;
-
-                } else {
-                    p->read_hunks = ce;
+                if (p->input_filter(p, ce->hunk) == NGX_ERROR) {
+                    return NGX_ABORT;
                 }
 
-                p->last_read_hunk = ce;
-
                 n -= size;
 
+                chain = ce->next;
+
             } else {
                 ce->hunk->last += n;
-                p->free_hunks = ce;
-
                 n = 0;
             }
         }
 
-        if (chain == p->free_hunks) {
-            chain = NULL;
-        }
+        p->free_raw_hunks = chain;
+    }
 
-        /*
-         * the input filter i.e. that moves HTTP/1.1 chunks
-         * from a read chain to an incoming chain
-         */
-
-        if (p->input_filter(p, chain) == NGX_ERROR) {
+    if ((p->upstream_eof || p->upstream_error) && p->free_raw_hunks) {
+        if (p->input_filter(p, p->free_raw_hunks->hunk) == NGX_ERROR) {
             return NGX_ABORT;
         }
 
-ngx_log_debug(p->log, "rest chain: %08X" _ ce);
-
-        /*
-         * if the rest hunks are file hunks then move them to a file chain
-         * otherwise add them to a free chain
-         */
-
-        if (rest) {
-            if (rest->hunk->shadow) {
-                p->file_hunks = rest;
-
-            } else {
-                if (p->free_hunks) {
-                    p->free_hunks->next = rest;
-
-                } else {
-                    p->free_hunks = rest;
-                }
-            }
-
-            break;
-        }
-    }
-
-ngx_log_debug(p->log, "eof: %d" _ p->upstream_eof);
-
-    /*
-     * if there's the end of upstream response then move
-     * the partially filled hunk from a free chain to an incoming chain
-     */
-
-    if (p->upstream_eof) {
-        if (p->free_hunks
-            && p->free_hunks->hunk->pos < p->free_hunks->hunk->last)
-        {
-
-#if (NGX_EVENT_COPY_FILTER)
-
-            if (p->input_filter(p, NULL) == NGX_ERROR) {
-                return NGX_ABORT;
-            }
-#else
-
-            if (p->input_filter) {
-                if (p->input_filter(p, NULL) == NGX_ERROR) {
-                    return NGX_ABORT;
-                }
-
-            } else {
-                ce = p->free_hunks;
-
-                if (p->in_hunks) {
-                    p->last_in_hunk->next = ce;
-
-                } else {
-                    p->in_hunks = ce;
-                }
-
-                p->last_in_hunk = ce;
-            }
-
-            p->free_hunks = ce->next;
-            ce->next = NULL;
-
-#endif  /* NGX_EVENT_COPY_FILTER */
-        }
-
-#if 0
-        /* free the unneeded hunks */
-
-        for (ce = p->free_hunks; ce; ce = ce->next) {
-            ngx_free_hunk(p->pool, ce->hunk);
-        }
-#endif
-
-        if (p->in_hunks) {
-            p->last_in_hunk->hunk->type |= NGX_HUNK_LAST;
-
-        } else if (p->out_hunks) {
-            p->last_out_hunk->hunk->type |= NGX_HUNK_LAST;
-        }
+        /* TODO: p->free_raw_hunk->next can be free()ed */
+        p->free_raw_hunks = p->free_raw_hunks->next;
     }
 
     if (p->cachable) {
-        if (p->in_hunks) {
+        if (p->in) {
             rc = ngx_event_proxy_write_chain_to_temp_file(p);
 
             if (rc != NGX_OK) {
@@ -353,13 +199,13 @@ ngx_log_debug(p->log, "eof: %d" _ p->ups
             }
         }
 
-        if (p->out_hunks && p->downstream->write->ready) {
+        if (p->out && p->downstream->write->ready) {
             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) {
+    } else if ((p->out || p->in) && p->downstream->write->ready) {
         if (ngx_event_proxy_write_to_downstream(p) == NGX_ABORT) {
             return NGX_ABORT;
         }
@@ -375,25 +221,22 @@ ngx_log_debug(p->log, "upstream level: %
         }
     }
 
-    if (p->upstream_eof) {
-        return NGX_OK;
-
-    } else {
-        return NGX_AGAIN;
-    }
+    return NGX_OK;
 }
 
 
 int ngx_event_proxy_write_to_downstream(ngx_event_proxy_t *p)
 {
-    ngx_chain_t                   *out, *ce;
+    int           rc;
+    ngx_hunk_t   *h;
+    ngx_chain_t  *out, *ce, *te;
 
     while (p->downstream->write->ready) {
 
         if (p->out) {
             out = p->out;
 
-            if (p->busy_len + ngx_hunk_size(out->hunk)) > p->max_busy_len) {
+            if (p->busy_len + ngx_hunk_size(out->hunk) > p->max_busy_len) {
                 break;
             }
 
@@ -403,7 +246,7 @@ int ngx_event_proxy_write_to_downstream(
         } else if (!p->cachable && p->in) {
             out = p->in;
 
-            if (p->busy_len + ngx_hunk_size(out->hunk)) > p->max_busy_len) {
+            if (p->busy_len + ngx_hunk_size(out->hunk) > p->max_busy_len) {
                 break;
             }
 
@@ -415,9 +258,9 @@ int ngx_event_proxy_write_to_downstream(
 
         out->next = NULL;
 
-        rc = p->output_filter(p->output_data, out->hunk);
+        rc = p->output_filter(p->output_ctx, out->hunk);
 
-        ngx_chain_update_chains(p->free, p->busy, out);
+        ngx_chain_update_chains(&p->free, &p->busy, &out);
 
         /* calculate p->busy_len */
 
@@ -435,14 +278,14 @@ int ngx_event_proxy_write_to_downstream(
                 h->shadow = NULL;
                 ngx_alloc_ce_and_set_hunk(te, ce->hunk->shadow, p->pool,
                                           NGX_ABORT);
-                ngx_add_after_partially_filled_hunk(p->free_raw_hunks, te);
+                ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te);
 
                 ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW;
             }
             ce->hunk->shadow = NULL;
         }
 
-        if (p->upstream.read->ready)
+        if (p->upstream->read->ready) {
             if (ngx_event_proxy_read_upstream(p) == NGX_ERROR) {
                 return NGX_ABORT;
             }
@@ -450,7 +293,8 @@ int ngx_event_proxy_write_to_downstream(
     }
 
     if (p->downstream_level == 0) {
-        if (ngx_handler_write_event(p->downstream->write) == NGX_ERROR) {
+        if (ngx_handle_write_event(p->downstream->write,
+                                           /* TODO: lowat */ 0) == NGX_ERROR) {
             return NGX_ABORT;
         }
     }
@@ -463,13 +307,13 @@ int ngx_event_proxy_write_to_downstream(
 }
 
 
-int ngx_event_proxy_write_chain_to_temp_file(ngx_event_proxy_t *p)
+static int ngx_event_proxy_write_chain_to_temp_file(ngx_event_proxy_t *p)
 {
     int           rc, size;
     ngx_hunk_t   *h;
-    ngx_chain_t  *entry, *next, *saved_in, *saved_read;
+    ngx_chain_t  *ce, *next, *in, **last;
 
-ngx_log_debug(p->log, "write to file");
+    ngx_log_debug(p->log, "write to file");
 
     if (p->temp_file->fd == NGX_INVALID_FILE) {
         rc = ngx_create_temp_file(p->temp_file, p->temp_path, p->pool,
@@ -483,86 +327,59 @@ ngx_log_debug(p->log, "write to file");
             return NGX_AGAIN;
         }
 
-        if (p->cachable == 0 && p->temp_file_warn) {
+        if (!p->cachable && p->temp_file_warn) {
             ngx_log_error(NGX_LOG_WARN, p->log, 0, p->temp_file_warn);
         }
     }
 
-    if (p->cachable == 0) {
+    if (!p->cachable) {
 
-        entry = p->read_hunks;
         size = 0;
+        ce = p->in;
 
         do {
-            size += entry->hunk->last - entry->hunk->pos;
+            size += ce->hunk->last - ce->hunk->pos;
             if (size >= p->temp_file_write_size) {
                 break;
             }
-            entry = entry->next;
+            ce = ce->next;
 
-        } while (entry);
-
-        saved_read = entry->next;
-        entry->next = NULL;
+        } while (ce);
 
-        if (saved_read) {
-            for (entry = p->in_hunks; entry->next; entry = entry->next) {
-                if (entry->next->hunk->shadow == saved_read->hunk) {
-                    break;
-                }
-            }
-            saved_in = entry->next;
-            entry->next = NULL;
-
-        } else {
-            saved_in = NULL;
-        }
+        in = ce->next;
+        last = &ce->next;
+        ce->next = NULL;
 
     } else {
-        saved_read = NULL;
-        saved_in = NULL;
+        in = NULL;
+        last = &p->in;
     }
 
-    if (ngx_write_chain_to_file(p->temp_file, p->in_hunks, p->temp_offset,
+    if (ngx_write_chain_to_file(p->temp_file, p->in, p->temp_offset,
                                 p->pool) == NGX_ERROR) {
         return NGX_ABORT;
     }
 
-    for (entry = p->in_hunks; entry; entry = next) {
-        next = entry->next;
-        entry->next = NULL;
+    for (ce = p->in; ce; ce = next) {
+        next = ce->next;
+        ce->next = NULL;
 
-        h = entry->hunk;
+        h = ce->hunk;
         h->type |= NGX_HUNK_FILE;
         h->file = p->temp_file;
         h->file_pos = p->temp_offset;
         p->temp_offset += h->last - h->pos;
         h->file_last = p->temp_offset;
 
-ngx_log_debug(p->log, "event proxy file hunk: %08X:%08X" _ h _ h->shadow);
-
         if (h->type & NGX_HUNK_LAST_SHADOW) {
-#if 0
-            h->shadow->last = h->shadow->pos;
-#else
             h->shadow->last = h->shadow->pos = h->shadow->start;
-#endif
         }
 
-        if (p->out_hunks) {
-            p->last_out_hunk->next = entry;
-
-        } else {
-            p->out_hunks = entry;
-        }
-
-        p->last_out_hunk = entry;
+        ngx_chain_add_ce(p->out, p->last_out, ce);
     }
 
-    p->file_hunks = p->read_hunks;
-
-    p->read_hunks = saved_read;
-    p->in_hunks = saved_in;
+    p->in = in;
+    p->last_in = last;
 
     return NGX_OK;
 }
@@ -593,22 +410,44 @@ int ngx_event_proxy_copy_input_filter(ng
     hunk->shadow = h;
 
     ngx_alloc_ce_and_set_hunk(ce, h, p->pool, NGX_ERROR);
-    ngx_chain_add_ce(p->in_hunk, p->last_in_hunk, ce);
+    ngx_chain_add_ce(p->in, p->last_in, ce);
 
     return NGX_OK;
 }
 
 
-ngx_inline static void ngx_remove_shadow_links(ngx_chain_t *ce)
+ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk)
 {
-    for (
+    ngx_hunk_t  *h, *next;
+
+    if (hunk->shadow == NULL) {
+        return;
+    }
+
+    h = hunk->shadow;
+
+    while (!(h->type & NGX_HUNK_LAST_SHADOW)) {
+        next = h->shadow;
+        h->type &= ~(NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY|NGX_HUNK_RECYCLED);
+        h->shadow = NULL;
+        h = next;
+    }
+
+    h->type &= ~(NGX_HUNK_TEMP
+                 |NGX_HUNK_IN_MEMORY
+                 |NGX_HUNK_RECYCLED
+                 |NGX_HUNK_LAST_SHADOW);
+    h->shadow = NULL;
+
+    hunk->shadow = NULL;
 }
 
 
-ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free;
-                                                       ngx_hunk_t *h);
+ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free,
+                                                       ngx_hunk_t *h)
 {
-    ngx_hunk_t  *s;
+    ngx_hunk_t   *s;
+    ngx_chain_t  *ce, **le;
 
     if (h->shadow == NULL) {
         return;
@@ -635,15 +474,20 @@ ngx_inline static void ngx_remove_shadow
 }
 
 
-ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t *chain,
+ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain,
                                                            ngx_chain_t *ce)
 {
-    if (chain->hunk->pos != chain->hunk->last) {
-        ce->next = chain->next;
-        chain->next = ce;
+    if (*chain == NULL) {
+        *chain = ce;
+        return;
+    }
+
+    if ((*chain)->hunk->pos != (*chain)->hunk->last) {
+        ce->next = (*chain)->next;
+        (*chain)->next = ce;
 
     } else {
-        ce->next = chain;
-        chain = ce;
+        ce->next = (*chain);
+        (*chain) = ce;
     }
 }
--- a/src/event/ngx_event_proxy.h
+++ b/src/event/ngx_event_proxy.h
@@ -10,40 +10,37 @@
 typedef struct ngx_event_proxy_s  ngx_event_proxy_t;
 
 typedef int (*ngx_event_proxy_input_filter_pt)(ngx_event_proxy_t *p,
-                                                          ngx_chain_t *chain);
+                                               ngx_hunk_t *hunk);
 typedef int (*ngx_event_proxy_output_filter_pt)(void *data, ngx_hunk_t *hunk);
 
 
 struct ngx_event_proxy_s {
-    ngx_chain_t       *read_hunks;
-    ngx_chain_t       *last_read_hunk;
-
-    ngx_chain_t       *file_hunks;
+    ngx_chain_t       *free_raw_hunks;
+    ngx_chain_t       *in;
+    ngx_chain_t      **last_in;
 
-    ngx_chain_t       *in_hunks;
-    ngx_chain_t       *last_in_hunk;
+    ngx_chain_t       *out;
+    ngx_chain_t      **last_out;
 
-    ngx_chain_t       *out_hunks;
-    ngx_chain_t       *last_out_hunk;
+    ngx_chain_t       *free;
+    ngx_chain_t       *busy;
 
-    ngx_chain_t       *free_hunks;
-#if 0
-    ngx_chain_t       *last_free_hunk;
-#endif
+    /*
+     * the input filter i.e. that moves HTTP/1.1 chunks
+     * from the raw hunks to an incoming chain
+     */
 
-    ngx_hunk_t        *busy_hunk;
+    ngx_event_proxy_input_filter_pt    input_filter;
+    void                              *input_ctx;
 
-    ngx_event_proxy_input_filter_pt   input_filter;
-    void              *input_data;
-
-    ngx_event_proxy_output_filter_pt  output_filter;
-    void              *output_data;
+    ngx_event_proxy_output_filter_pt   output_filter;
+    void                              *output_ctx;
 
     unsigned           cachable:1;
-    unsigned           block_upstream:1;
+    unsigned           upstream_done:1;
     unsigned           upstream_eof:1;
     unsigned           upstream_error:1;
-    unsigned           downstream_eof:1;
+    unsigned           downstream_done:1;
     unsigned           downstream_error:1;
 
     int                upstream_level;
@@ -52,6 +49,9 @@ struct ngx_event_proxy_s {
     int                hunks;
     ngx_bufs_t         bufs;
 
+    size_t             busy_len;
+    size_t             max_busy_len;
+
     off_t              temp_offset;
     off_t              max_temp_file_size;
     int                temp_file_write_size;
@@ -63,9 +63,6 @@ struct ngx_event_proxy_s {
     ngx_log_t         *log;
 
     ngx_chain_t       *preread_hunks;
-#if 0
-    ngx_chain_t       *last_preread_hunk;
-#endif
     int                preread_size;
 
     ngx_file_t        *temp_file;
@@ -76,7 +73,7 @@ struct ngx_event_proxy_s {
 
 int ngx_event_proxy_read_upstream(ngx_event_proxy_t *p);
 int ngx_event_proxy_write_to_downstream(ngx_event_proxy_t *p);
-int ngx_event_proxy_copy_input_filter(ngx_event_proxy_t *p, ngx_chain_t *chain);
+int ngx_event_proxy_copy_input_filter(ngx_event_proxy_t *p, ngx_hunk_t *hunk);
 
 
 #endif /* _NGX_EVENT_PROXY_H_INCLUDED_ */
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -79,7 +79,7 @@ ngx_module_t  ngx_http_index_module = {
 
 int ngx_http_index_handler(ngx_http_request_t *r)
 {
-    int                        i, rc, test_dir, path_not_found;
+    int                        rc;
     char                      *name, *file;
     ngx_str_t                  redirect, *index;
     ngx_err_t                  err;
@@ -132,7 +132,7 @@ int ngx_http_index_handler(ngx_http_requ
 
         fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN);
 
-        if (fd == NGX_AGAIN) {
+        if (fd == (ngx_fd_t) NGX_AGAIN) {
             return NGX_AGAIN;
         }
 
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -4,7 +4,188 @@
 #include <ngx_http.h>
 
 
-int ngx_http_static_handler(ngx_http_request_t *r)
+static int ngx_http_static_handler(ngx_http_request_t *r);
+static int ngx_http_static_init(ngx_cycle_t *cycle);
+
+
+static ngx_command_t  ngx_http_static_commands[] = {
+
+    ngx_null_command
+};
+
+
+
+ngx_http_module_t  ngx_http_static_module_ctx = {
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+    
+    NULL,                                  /* create server configuration */
+    NULL,                                  /* merge server configuration */
+    
+    NULL,                                  /* create location configuration */
+    NULL                                   /* merge location configuration */
+};  
+
+
+ngx_module_t  ngx_http_static_module = {
+    NGX_MODULE,
+    &ngx_http_static_module_ctx,           /* module context */
+    ngx_http_static_commands,              /* module directives */
+    NGX_HTTP_MODULE,                       /* module type */
+    ngx_http_static_init,                  /* init module */
+    NULL                                   /* init child */
+};
+
+
+int ngx_http_static_translate_handler(ngx_http_request_t *r)
+{
+    char                      *location, *last;
+    ngx_err_t                  err;
+    ngx_table_elt_t           *h;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+        return NGX_HTTP_NOT_ALLOWED;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (r->uri.data[r->uri.len - 1] == '/') {
+        if (r->path.data == NULL) {
+            ngx_test_null(r->path.data,
+                          ngx_palloc(r->pool,
+                                     clcf->doc_root.len + r->uri.len),
+                          NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+            ngx_cpystrn(ngx_cpymem(r->path.data, clcf->doc_root.data,
+                                   clcf->doc_root.len),
+                        r->uri.data, r->uri.len + 1);
+
+        } else {
+            r->path.data[r->path.len] = '\0';
+        }
+
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "directory index of \"%s\" is forbidden", r->path.data);
+
+        return NGX_HTTP_FORBIDDEN;
+    }
+
+    /* "+ 2" is for trailing '/' in redirect and '\0' */
+    ngx_test_null(r->file.name.data,
+                  ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len + 2),
+                  NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+    location = ngx_cpymem(r->file.name.data, clcf->doc_root.data,
+                          clcf->doc_root.len),
+
+    last = ngx_cpystrn(location, r->uri.data, r->uri.len + 1);
+
+ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->file.name.data);
+
+#if (WIN9X)
+
+    /*
+     * There is no way to open a file or a directory in Win9X with
+     * one syscall: Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag.
+     * so we need to check its type before the opening
+     */
+
+    r->file.info.dwFileAttributes = GetFileAttributes(r->file.name.data);
+    if (r->file.info.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
+        err = ngx_errno;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
+                      ngx_file_type_n " \"%s\" failed", r->file.name.data);
+
+        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+            return NGX_HTTP_NOT_FOUND;
+
+        } else if (err == NGX_EACCES) {
+            return NGX_HTTP_FORBIDDEN;
+
+        } else {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+#else
+
+    if (r->file.fd == NGX_INVALID_FILE) {
+        r->file.fd = ngx_open_file(r->file.name.data,
+                                   NGX_FILE_RDONLY, NGX_FILE_OPEN);
+    }
+
+    if (r->file.fd == NGX_INVALID_FILE) {
+        err = ngx_errno;
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+                      ngx_open_file_n " \"%s\" failed", r->file.name.data);
+
+        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
+            return NGX_HTTP_NOT_FOUND;
+
+        } else if (err == NGX_EACCES) {
+            return NGX_HTTP_FORBIDDEN;
+
+        } else {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd);
+
+    if (!r->file.info_valid) {
+        if (ngx_stat_fd(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+                          ngx_stat_fd_n " \"%s\" failed", r->file.name.data);
+
+            if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                              ngx_close_file_n " \"%s\" failed",
+                              r->file.name.data);
+            }
+
+            r->file.fd = NGX_INVALID_FILE;
+
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        r->file.info_valid = 1;
+    }
+#endif
+
+    if (ngx_is_dir(r->file.info)) {
+ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
+
+#if !(WIN9X)
+        if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+                          ngx_close_file_n " \"%s\" failed", r->file.name.data);
+        }
+
+        r->file.fd = NGX_INVALID_FILE;
+#endif
+
+        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 - location;
+        h->value.data = location;
+        r->headers_out.location = h;
+
+        return NGX_HTTP_MOVED_PERMANENTLY;
+    }
+
+    r->content_handler = ngx_http_static_handler;
+
+    return NGX_OK;
+}
+
+
+static int ngx_http_static_handler(ngx_http_request_t *r)
 {
     int                        rc, key, i;
     ngx_log_e                  level;
@@ -20,10 +201,6 @@ int ngx_http_static_handler(ngx_http_req
         return rc;
     }
 
-    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
-        return NGX_HTTP_NOT_ALLOWED;
-    }
-
     ctx = r->connection->log->data;
     ctx->action = "sending response";
 
@@ -142,3 +319,22 @@ int ngx_http_static_handler(ngx_http_req
 
     return ngx_http_output_filter(r, h);
 }
+
+
+static int ngx_http_static_init(ngx_cycle_t *cycle)
+{
+    ngx_http_handler_pt        *h;
+    ngx_http_conf_ctx_t        *ctx;
+    ngx_http_core_main_conf_t  *cmcf;
+    
+    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->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
+                  NGX_ERROR);
+    *h = ngx_http_static_translate_handler;
+
+    return NGX_OK;
+}
+
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -17,7 +17,8 @@ static void ngx_http_proxy_process_upstr
 static void ngx_http_proxy_process_upstream_headers(ngx_event_t *rev);
 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *);
 static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_process_upstream_body(ngx_event_t *rev);
+static void ngx_http_proxy_process_upstream(ngx_event_t *rev);
+static void ngx_http_proxy_process_downstream(ngx_event_t *wev);
 
 static int ngx_http_proxy_parse_status_line(ngx_http_proxy_ctx_t *p);
 static void ngx_http_proxy_next_upstream(ngx_http_proxy_ctx_t *p);
@@ -27,8 +28,21 @@ static void ngx_http_proxy_close_connect
 static int ngx_http_proxy_init(ngx_cycle_t *cycle);
 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
 
+static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+                                     void *conf);
+static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
+                                           ngx_http_proxy_upstream_t *u);
+
 
 static ngx_command_t ngx_http_proxy_commands[] = {
+
+    {ngx_string("proxy_pass"),
+     NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+     ngx_http_proxy_set_pass,
+     NGX_HTTP_LOC_CONF_OFFSET,
+     0,
+     NULL},
+
     ngx_null_command
 };
 
@@ -54,7 +68,7 @@ ngx_module_t  ngx_http_proxy_module = {
     &ngx_http_proxy_module_ctx,            /* module context */
     ngx_http_proxy_commands,               /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
-    ngx_http_proxy_init,                   /* init module */
+    NULL,                                  /* init module */
     NULL                                   /* init child */
 };
 
@@ -99,22 +113,9 @@ static char conn_close_header[] = "Conne
 
 
 
-static int ngx_http_proxy_translate_handler(ngx_http_request_t *r)
-{
-#if 0
-    r->handler = ngx_http_proxy_handler;
-    return NGX_OK;
-#else
-    return NGX_DECLINED;
-#endif
-}
-
-
 static int ngx_http_proxy_handler(ngx_http_request_t *r)
 {
-    int                         rc;
-    ngx_http_proxy_ctx_t       *p;
-    ngx_http_proxy_loc_conf_t  *lcf;
+    ngx_http_proxy_ctx_t  *p;
 
     ngx_http_create_ctx(r, p, ngx_http_proxy_module,
                         sizeof(ngx_http_proxy_ctx_t),
@@ -126,6 +127,8 @@ static int ngx_http_proxy_handler(ngx_ht
 
     p->request = r;
     p->method = r->method;
+
+    /* TODO: from lcf->upstream */
     p->uri.data = "/";
     p->uri.len = 1;
     p->location_len = 1;
@@ -144,7 +147,7 @@ static int ngx_http_proxy_handler(ngx_ht
 
     ngx_http_proxy_send_request(p);
 
-    return NGX_OK;
+    return NGX_DONE;
 }
 
 
@@ -580,7 +583,6 @@ static void ngx_http_proxy_process_upstr
 
 static ssize_t ngx_http_proxy_read_upstream_header(ngx_http_proxy_ctx_t *p)
 {
-    int           event;
     ssize_t       n;
     ngx_event_t  *rev;
 
@@ -589,7 +591,10 @@ static ssize_t ngx_http_proxy_read_upstr
     n = p->header_in->last - p->header_in->pos;
 
     if (n > 0) {
+#if 0
+        /* TODO THINK */
         rev->ready = 0;
+#endif
         return n;
     }
 
@@ -700,11 +705,12 @@ static void ngx_http_proxy_send_response
         return;
     }
 
+    ep->input_filter = ngx_event_proxy_copy_input_filter;
     ep->output_filter = (ngx_event_proxy_output_filter_pt)
                                                         ngx_http_output_filter;
-    ep->output_data = r;
-    ep->block_size = p->lcf->block_size;
-    ep->max_block_size = p->lcf->max_block_size;
+    ep->output_ctx = r;
+    ep->bufs = p->lcf->bufs;
+    ep->max_busy_len = p->lcf->max_busy_len;
     ep->upstream = p->upstream.connection;
     ep->downstream = r->connection;
     ep->pool = r->pool;
@@ -742,16 +748,18 @@ static void ngx_http_proxy_send_response
     lcx->action = "reading an upstream";
 #endif
 
-    ngx_event_proxy_read_upstream(ep);
+    p->upstream.connection->read->event_handler =
+                                               ngx_http_proxy_process_upstream;
+    r->connection->write->event_handler =
+                                             ngx_http_proxy_process_downstream;
 
-    p->upstream.connection->read->event_handler =
-                                          ngx_http_proxy_process_upstream_body;
+    ngx_http_proxy_process_upstream(p->upstream.connection->read);
 
     return;
 }
 
 
-static void ngx_http_proxy_process_upstream_body(ngx_event_t *rev)
+static void ngx_http_proxy_process_upstream(ngx_event_t *rev)
 {
     ngx_connection_t      *c;
     ngx_http_proxy_ctx_t  *p;
@@ -759,25 +767,58 @@ static void ngx_http_proxy_process_upstr
     c = rev->data;
     p = c->data;
 
-    ngx_log_debug(rev->log, "http proxy process upstream body");
+    ngx_log_debug(rev->log, "http proxy process upstream");
 
     if (rev->timedout) {
-        ngx_http_proxy_close_connection(p->upstream.connection);
+        ngx_http_proxy_close_connection(c);
         p->upstream.connection = NULL;
         return;
     }
 
-    ngx_event_proxy_read_upstream(p->event_proxy);
+    if (ngx_event_proxy_read_upstream(p->event_proxy) == NGX_ABORT) {
+        ngx_http_proxy_finalize_request(p, 0);
+        return;
+    }
 
-    if (p->event_proxy->upstream_eof) {
-        ngx_http_proxy_close_connection(p->upstream.connection);
-        p->upstream.connection = NULL;
+    if (p->event_proxy->upstream_eof
+        || p->event_proxy->upstream_error
+        || p->event_proxy->upstream_done)
+    {
+        ngx_http_proxy_finalize_request(p, ngx_http_send_last(p->request));
         return;
     }
 
-    if (p->event_proxy->upstream_error) {
-        ngx_http_proxy_close_connection(p->upstream.connection);
-        p->upstream.connection = NULL;
+    return;
+}
+
+
+static void ngx_http_proxy_process_downstream(ngx_event_t *wev)
+{
+    ngx_connection_t      *c;
+    ngx_http_proxy_ctx_t  *p;
+
+    c = wev->data;
+    p = c->data;
+
+    ngx_log_debug(wev->log, "http proxy process downstream");
+
+    if (wev->timedout) {
+        ngx_http_close_connection(c);
+        return;
+    }
+
+    if (ngx_event_proxy_write_to_downstream(p->event_proxy) == NGX_ABORT) {
+        ngx_http_proxy_finalize_request(p, 0);
+        return;
+    }
+
+    if (p->event_proxy->downstream_done) {
+        ngx_http_proxy_finalize_request(p, 0);
+        return;
+    }
+
+    if (p->event_proxy->downstream_error) {
+        ngx_http_close_connection(c);
         return;
     }
 
@@ -1076,25 +1117,6 @@ static size_t ngx_http_proxy_log_error(v
 }
 
 
-static int ngx_http_proxy_init(ngx_cycle_t *cycle)
-{
-    ngx_http_handler_pt        *h;
-    ngx_http_conf_ctx_t        *ctx;
-    ngx_http_core_main_conf_t  *cmcf;
-
-    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->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
-                  NGX_ERROR);
-
-    *h = ngx_http_proxy_translate_handler;
-
-    return NGX_OK;
-}
-
-
 static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
 {
     int                         i;
@@ -1121,8 +1143,9 @@ static void *ngx_http_proxy_create_loc_c
     conf->header_size = 4096;
     conf->read_timeout = 30000;
 
-    conf->block_size = 4096;
-    conf->max_block_size = 4096 * 3;
+    conf->bufs.num = 10;
+    conf->bufs.size = 4096;
+    conf->max_busy_len = 8192 + 4096;
     conf->max_temp_file_size = 4096 * 5;
     conf->temp_file_write_size = 4096 * 2;
 
@@ -1147,3 +1170,206 @@ static void *ngx_http_proxy_create_loc_c
 
     return conf;
 }
+
+
+static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd,
+                                     void *conf)
+{
+    ngx_http_proxy_loc_conf_t *lcf = conf;
+
+    int                        i, len;
+    char                      *err, *host;
+    ngx_str_t                 *value;
+    struct hostent            *h;
+    u_int32_t                  addr;
+    ngx_http_conf_ctx_t       *ctx;
+    ngx_http_core_loc_conf_t  *clcf;
+
+
+    value = cf->args->elts;
+
+    if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) {
+        return "invalid URL prefix";
+    }
+
+    ngx_test_null(lcf->upstream,
+                  ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_upstream_t)),
+                  NGX_CONF_ERROR);
+
+    value[1].data += 7;
+    value[1].len -= 7;
+
+    err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream);
+
+    if (err) {
+        return err;
+    }
+
+    ngx_test_null(host, ngx_palloc(cf->pool, lcf->upstream->host.len + 1),
+                  NGX_CONF_ERROR);
+    ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1);
+
+    addr = inet_addr(host);
+
+    if (addr == INADDR_NONE) {
+        h = gethostbyname(host);
+
+        if (h == NULL || h->h_addr_list[0] == NULL) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host);
+            return NGX_CONF_ERROR;
+        }
+
+        for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
+
+        /* MP: ngx_shared_palloc() */
+
+        ngx_test_null(lcf->peers,
+                      ngx_pcalloc(cf->pool,
+                                  sizeof(ngx_peers_t)
+                                  + sizeof(ngx_peer_t) * (i - 1)),
+                      NGX_CONF_ERROR);
+
+        lcf->peers->number = i;
+
+        for (i = 0; h->h_addr_list[i] != NULL; i++) {
+            lcf->peers->peers[i].host.data = host;
+            lcf->peers->peers[i].host.len = lcf->upstream->host.len;
+            lcf->peers->peers[i].addr = *(u_int32_t *)(h->h_addr_list[i]);
+            lcf->peers->peers[i].port = lcf->upstream->port;
+
+            len = INET_ADDRSTRLEN + lcf->upstream->port_text.len + 1;
+            ngx_test_null(lcf->peers->peers[i].addr_port_text.data,
+                          ngx_palloc(cf->pool, len),
+                          NGX_CONF_ERROR);
+
+            len = ngx_inet_ntop(AF_INET,
+                                (char *) &lcf->peers->peers[i].addr,
+                                lcf->peers->peers[i].addr_port_text.data,
+                                len);
+
+            lcf->peers->peers[i].addr_port_text.data[len++] = ':';
+
+            ngx_cpystrn(lcf->peers->peers[i].addr_port_text.data + len,
+                        lcf->upstream->port_text.data,
+                        lcf->upstream->port_text.len + 1);
+
+            lcf->peers->peers[i].addr_port_text.len =
+                                        len + lcf->upstream->port_text.len + 1;
+        }
+
+    } else {
+
+        /* MP: ngx_shared_palloc() */
+
+        ngx_test_null(lcf->peers, ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)),
+                      NGX_CONF_ERROR);
+
+        lcf->peers->number = 1;
+
+        lcf->peers->peers[0].host.data = host;
+        lcf->peers->peers[0].host.len = lcf->upstream->host.len;
+        lcf->peers->peers[0].addr = addr;
+        lcf->peers->peers[0].port = lcf->upstream->port;
+
+        len = lcf->upstream->host.len + lcf->upstream->port_text.len + 1;
+
+        ngx_test_null(lcf->peers->peers[0].addr_port_text.data,
+                      ngx_palloc(cf->pool, len + 1),
+                      NGX_CONF_ERROR);
+
+        len = lcf->upstream->host.len;
+
+        ngx_memcpy(lcf->peers->peers[0].addr_port_text.data,
+                   lcf->upstream->host.data, len);
+
+        lcf->peers->peers[0].addr_port_text.data[len++] = ':';
+
+        ngx_cpystrn(lcf->peers->peers[0].addr_port_text.data + len,
+                    lcf->upstream->port_text.data,
+                    lcf->upstream->port_text.len + 1);
+    }
+
+    ctx = cf->ctx;
+    clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
+    lcf->upstream->location = &clcf->name;
+    clcf->handler = ngx_http_proxy_handler;
+
+    return NULL;
+}
+
+static char *ngx_http_proxy_parse_upstream(ngx_str_t *url,
+                                           ngx_http_proxy_upstream_t *u)
+{
+    size_t  i;
+
+    if (url->data[0] == ':' || url->data[0] == '/') {
+        return "invalid upstream URL";
+    }
+
+    u->host.data = url->data;
+    u->host_header.data = url->data;
+
+    for (i = 1; i < url->len; i++) {
+        if (url->data[i] == ':') {
+            u->port_text.data = &url->data[i] + 1;
+            u->host.len = i;
+        }
+
+        if (url->data[i] == '/') {
+            u->uri.data = &url->data[i];
+            u->uri.len = url->len - i;
+            u->host_header.len = i;
+
+            if (u->host.len == 0) {
+                u->host.len = i;
+            }
+
+            if (u->port_text.data == NULL) {
+                u->port = htons(80);
+                u->port_text.len = 2;
+                u->port_text.data = "80";
+                return NULL;
+            }
+
+            u->port_text.len = &url->data[i] - u->port_text.data;
+
+            if (u->port_text.len > 0) {
+                u->port = ngx_atoi(u->port_text.data, u->port_text.len);
+                if (u->port > 0) {
+                    u->port = htons((u_short) u->port);
+                    return NULL;
+                }
+            }
+
+            return "invalid port in upstream URL";
+        }
+    }
+
+    if (u->host.len == 0) {
+        u->host.len = i;
+    }
+
+    u->host_header.len = i;
+
+    u->uri.data = "/";
+    u->uri.len = 1;
+
+    if (u->port_text.data == NULL) {
+        u->port = htons(80);
+        u->port_text.len = 2;
+        u->port_text.data = "80";
+        return NULL;
+    }
+
+    u->port_text.len = &url->data[i] - u->port_text.data;
+
+    if (u->port_text.len > 0) {
+        u->port = ngx_atoi(u->port_text.data, u->port_text.len);
+        if (u->port > 0) {
+            u->port = htons((u_short) u->port);
+            return NULL;
+        }
+    }
+
+    return "invalid port in upstream URL";
+}
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -9,21 +9,33 @@
 
 
 typedef struct {
-    ngx_msec_t    connect_timeout;
-    ngx_msec_t    send_timeout;
-    ssize_t       header_size;
-    ngx_msec_t    read_timeout;
+    ngx_str_t   host;
+    ngx_str_t   uri;
+    ngx_str_t  *location;
+    ngx_str_t   host_header;
+    ngx_str_t   port_text;
+    int         port;
+} ngx_http_proxy_upstream_t;
+
+
+typedef struct {
+    ngx_msec_t                  connect_timeout;
+    ngx_msec_t                  send_timeout;
+    ssize_t                     header_size;
+    ngx_msec_t                  read_timeout;
+
+    ngx_bufs_t                  bufs;
 
     /* STUB */
-    int           block_size;
-    int           max_block_size;
-    int           max_temp_file_size;
-    int           temp_file_write_size;
+    int                         max_busy_len;
+    int                         max_temp_file_size;
+    int                         temp_file_write_size;
     /* */
 
-    ngx_path_t   *temp_path;
+    ngx_path_t                 *temp_path;
 
-    ngx_peers_t  *peers;
+    ngx_http_proxy_upstream_t  *upstream;
+    ngx_peers_t                *peers;
 } ngx_http_proxy_loc_conf_t;
 
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -6,9 +6,6 @@
 #include <nginx.h>
 
 
-/* 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);
@@ -304,7 +301,6 @@ static void ngx_http_run_phases(ngx_http
         return;
     }
 
-    /* TODO: no handlers found ? */
     ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
     return;
 }
@@ -346,164 +342,20 @@ ngx_log_debug(r->connection->log, "rc: %
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if ((ngx_io.flags & NGX_IO_SENDFILE) == 0 || clcf->sendfile == 0) {
+    if (!(ngx_io.flags & NGX_IO_SENDFILE) || !clcf->sendfile) {
         r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY;
     }
 
-    return NGX_OK;
-}
-
-
-int ngx_http_core_translate_handler(ngx_http_request_t *r)
-{
-    char                       *location, *last;
-    ngx_err_t                   err;
-    ngx_table_elt_t            *h;
-    ngx_http_core_srv_conf_t   *cscf;
-    ngx_http_core_loc_conf_t   *clcf;
-
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     if (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] == '/') {
-        if (r->path.data == NULL) {
-            ngx_test_null(r->path.data,
-                          ngx_palloc(r->pool,
-                                     clcf->doc_root.len + r->uri.len),
-                          NGX_HTTP_INTERNAL_SERVER_ERROR);
-
-            ngx_cpystrn(ngx_cpymem(r->path.data, clcf->doc_root.data,
-                                   clcf->doc_root.len),
-                        r->uri.data, r->uri.len + 1);
-
-        } else {
-            r->path.data[r->path.len] = '\0';
-        }
-
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "directory index of \"%s\" is forbidden", r->path.data);
-
-        return NGX_HTTP_FORBIDDEN;
-    }
-
-    /* "+ 2" is for trailing '/' in redirect and '\0' */
-    ngx_test_null(r->file.name.data,
-                  ngx_palloc(r->pool, clcf->doc_root.len + r->uri.len + 2),
-                  NGX_HTTP_INTERNAL_SERVER_ERROR);
-
-    location = ngx_cpymem(r->file.name.data, clcf->doc_root.data,
-                          clcf->doc_root.len),
-
-    last = ngx_cpystrn(location, r->uri.data, r->uri.len + 1);
-
-ngx_log_debug(r->connection->log, "HTTP filename: '%s'" _ r->file.name.data);
-
-#if (WIN9X)
-
-    /*
-     * There is no way to open a file or a directory in Win9X with
-     * one syscall: Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag.
-     * so we need to check its type before the opening
-     */
-
-    r->file.info.dwFileAttributes = GetFileAttributes(r->file.name.data);
-    if (r->file.info.dwFileAttributes == INVALID_FILE_ATTRIBUTES) {
-        err = ngx_errno;
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                      ngx_file_type_n " \"%s\" failed", r->file.name.data);
-
-        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
-            return NGX_HTTP_NOT_FOUND;
-
-        } else if (err == NGX_EACCES) {
-            return NGX_HTTP_FORBIDDEN;
+        /*
+         * if the location already has content handler then skip
+         * the translation phase
+         */
 
-        } else {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-    }
-
-#else
-
-    if (r->file.fd == NGX_INVALID_FILE) {
-        r->file.fd = ngx_open_file(r->file.name.data,
-                                   NGX_FILE_RDONLY, NGX_FILE_OPEN);
-    }
-
-    if (r->file.fd == NGX_INVALID_FILE) {
-        err = ngx_errno;
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
-                      ngx_open_file_n " \"%s\" failed", r->file.name.data);
-
-        if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
-            return NGX_HTTP_NOT_FOUND;
-
-        } else if (err == NGX_EACCES) {
-            return NGX_HTTP_FORBIDDEN;
-
-        } else {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
+        r->content_handler = clcf->handler;
+        r->phase++;
     }
 
-ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd);
-
-    if (!r->file.info_valid) {
-        if (ngx_stat_fd(r->file.fd, &r->file.info) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_stat_fd_n " \"%s\" failed", r->file.name.data);
-
-            if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-                ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                              ngx_close_file_n " \"%s\" failed",
-                              r->file.name.data);
-            }
-
-            r->file.fd = NGX_INVALID_FILE;
-
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
-        }
-
-        r->file.info_valid = 1;
-    }
-#endif
-
-    if (ngx_is_dir(r->file.info)) {
-ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
-
-#if !(WIN9X)
-        if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
-                          ngx_close_file_n " \"%s\" failed", r->file.name.data);
-        }
-
-        r->file.fd = NGX_INVALID_FILE;
-#endif
-
-        /* 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 - location;
-        h->value.data = location;
-        r->headers_out.location = h;
-
-        return NGX_HTTP_MOVED_PERMANENTLY;
-    }
-
-    r->content_handler = ngx_http_static_handler;
-
     return NGX_OK;
 }
 
@@ -609,18 +461,15 @@ int ngx_http_delay_handler(ngx_http_requ
 
 static int ngx_http_core_init(ngx_cycle_t *cycle)
 {
+#if 0
     ngx_http_handler_pt        *h;
+#endif
     ngx_http_conf_ctx_t        *ctx;
     ngx_http_core_main_conf_t  *cmcf;
 
     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->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
-                  NGX_ERROR);
-    *h = ngx_http_core_translate_handler;
-
 #if 0
     ngx_test_null(h, ngx_push_array(
                              &cmcf->phases[NGX_HTTP_TRANSLATE_PHASE].handlers),
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -765,7 +765,7 @@ void ngx_http_finalize_request(ngx_http_
 {
     ngx_log_debug(r->connection->log, "finalize http request");
 
-    if (r->main || r->closed) {
+    if (rc == NGX_DONE || r->main || r->closed) {
         return;
     }
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -163,11 +163,11 @@ int ngx_http_special_response_handler(ng
 
     } else if (error < NGX_HTTP_INTERNAL_SERVER_ERROR) {
         /* 4XX */
-        err = error - NGX_HTTP_BAD_REQUEST + 4;
+        err = error - NGX_HTTP_BAD_REQUEST + 3;
 
     } else {
         /* 5XX */
-        err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 4 + 17;
+        err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 3 + 17;
     }
 
     if (r->keepalive != 0) {
--- a/src/os/unix/ngx_recv.c
+++ b/src/os/unix/ngx_recv.c
@@ -22,8 +22,8 @@ ssize_t ngx_unix_recv(ngx_connection_t *
 
         if (rev->available == 0) {
             if (rev->eof) {
+                rev->ready = 0;
                 if (rev->error) {
-                    rev->ready = 0;
                     ngx_set_socket_errno(rev->error);
                     return ngx_unix_recv_error(rev, rev->error);
                 }
@@ -44,7 +44,10 @@ ssize_t ngx_unix_recv(ngx_connection_t *
             if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
                 rev->available -= n;
                 if (rev->available <= 0) {
-                    rev->ready = 0;
+                    if (!rev->eof) {
+                        rev->ready = 0;
+                    }
+
                     if (rev->available < 0) {
                         rev->available = 0;
                     }