changeset 314:d71c87d11b16

nginx-0.0.3-2004-04-14-09:57:36 import
author Igor Sysoev <igor@sysoev.ru>
date Wed, 14 Apr 2004 05:57:36 +0000
parents 98f1a8028067
children 39b6f2df45c0
files src/core/nginx.c src/core/ngx_conf_file.c src/core/ngx_conf_file.h src/event/modules/ngx_poll_module.c src/event/modules/ngx_select_module.c src/http/modules/ngx_http_gzip_filter.c src/http/modules/ngx_http_range_filter.c src/http/modules/proxy/ngx_http_proxy_upstream.c src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h
diffstat 11 files changed, 413 insertions(+), 148 deletions(-) [+]
line wrap: on
line diff
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -85,10 +85,6 @@ int main(int argc, char *const *argv)
     ngx_cycle_t       *cycle, init_cycle;
     ngx_core_conf_t   *ccf;
     ngx_master_ctx_t   ctx;
-#if !(WIN32)
-    size_t             len;
-    u_char             pid[/* STUB */ 10];
-#endif
 
 #if __FreeBSD__
     ngx_debug_init();
@@ -111,10 +107,6 @@ int main(int argc, char *const *argv)
     init_cycle.log = log;
     ngx_cycle = &init_cycle;
 
-#if 0
-    /* STUB */ log->log_level = NGX_LOG_DEBUG_ALL;
-#endif
-
     ngx_memzero(&ctx, sizeof(ngx_master_ctx_t));
     ctx.argc = argc;
     ctx.argv = argv;
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -577,7 +577,7 @@ char *ngx_conf_set_flag_slot(ngx_conf_t 
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     if (ngx_strcasecmp(value[1].data, "on") == 0) {
         flag = 1;
@@ -611,7 +611,7 @@ char *ngx_conf_set_str_slot(ngx_conf_t *
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     *field = value[1];
 
@@ -634,7 +634,7 @@ char *ngx_conf_set_num_slot(ngx_conf_t *
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
     *np = ngx_atoi(value[1].data, value[1].len);
     if (*np == NGX_ERROR) {
         return "invalid number";
@@ -663,7 +663,7 @@ char *ngx_conf_set_size_slot(ngx_conf_t 
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     *sp = ngx_parse_size(&value[1]);
     if (*sp == (size_t) NGX_ERROR) {
@@ -693,7 +693,7 @@ char *ngx_conf_set_msec_slot(ngx_conf_t 
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     *msp = ngx_parse_time(&value[1], 0);
     if (*msp == (ngx_msec_t) NGX_ERROR) {
@@ -727,7 +727,7 @@ char *ngx_conf_set_sec_slot(ngx_conf_t *
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     *sp = ngx_parse_time(&value[1], 1);
     if (*sp == NGX_ERROR) {
@@ -760,7 +760,7 @@ char *ngx_conf_set_bufs_slot(ngx_conf_t 
         return "is duplicate";
     }
 
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
 
     bufs->num = ngx_atoi(value[1].data, value[1].len);
     if (bufs->num == NGX_ERROR || bufs->num == 0) {
@@ -776,6 +776,42 @@ char *ngx_conf_set_bufs_slot(ngx_conf_t 
 }
 
 
+char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    char  *p = conf;
+
+    ngx_uint_t       *np, i;
+    ngx_str_t        *value;
+    ngx_conf_enum_t  *e;
+
+    np = (ngx_uint_t *) (p + cmd->offset);
+
+    if (*np != NGX_CONF_UNSET_UINT) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+    e = cmd->post;
+
+    for (i = 0; e[i].name.len != 0; i++) {
+        if (e[i].name.len != value[1].len
+            || ngx_strcasecmp(e[i].name.data, value[1].data) != 0)
+        {
+            continue;
+        }
+
+        *np = e[i].value;
+
+        return NGX_CONF_OK;
+    }
+
+    ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                       "invalid value \"%s\"", value[1].data);
+
+    return NGX_CONF_ERROR;
+}
+
+
 char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
@@ -786,14 +822,14 @@ char *ngx_conf_set_bitmask_slot(ngx_conf
 
 
     np = (ngx_uint_t *) (p + cmd->offset);
-    value = (ngx_str_t *) cf->args->elts;
+    value = cf->args->elts;
     mask = cmd->post;
 
     for (i = 1; i < cf->args->nelts; i++) {
         for (m = 0; mask[m].name.len != 0; m++) {
 
             if (mask[m].name.len != value[i].len
-                && ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
+                || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
             {
                 continue;
             }
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -42,6 +42,7 @@
 
 
 #define NGX_CONF_UNSET       -1
+#define NGX_CONF_UNSET_UINT  (ngx_uint_t) -1
 #define NGX_CONF_UNSET_SIZE  (size_t) -1
 #define NGX_CONF_UNSET_MSEC  (ngx_msec_t) -1
 
@@ -151,11 +152,17 @@ typedef struct {
 } ngx_conf_num_bounds_t;
 
 
+typedef struct {
+    ngx_str_t   name;
+    ngx_uint_t  value;
+} ngx_conf_enum_t;
+
+
 #define NGX_CONF_BITMASK_SET  1
 
 typedef struct {
-    ngx_str_t  name;
-    int        mask;
+    ngx_str_t   name;
+    ngx_uint_t  mask;
 } ngx_conf_bitmask_t;
 
 
@@ -196,6 +203,11 @@ char *ngx_conf_check_num_bounds(ngx_conf
         conf = (prev == NGX_CONF_UNSET) ? default : prev;                    \
     }
 
+#define ngx_conf_merge_unsigned_value(conf, prev, default)                   \
+    if (conf == NGX_CONF_UNSET_UINT) {                                       \
+        conf = (prev == NGX_CONF_UNSET_UINT) ? default : prev;               \
+    }
+
 #define ngx_conf_merge_msec_value(conf, prev, default)                       \
     if (conf == NGX_CONF_UNSET_MSEC) {                                       \
         conf = (prev == NGX_CONF_UNSET_MSEC) ? default : prev;               \
@@ -258,6 +270,7 @@ char *ngx_conf_set_msec_slot(ngx_conf_t 
 char *ngx_conf_set_sec_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_time_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_bufs_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_enum_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 char *ngx_conf_set_bitmask_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
--- a/src/event/modules/ngx_poll_module.c
+++ b/src/event/modules/ngx_poll_module.c
@@ -66,7 +66,8 @@ static int ngx_poll_init(ngx_cycle_t *cy
         nevents = 0;
     }
 
-    if (cycle->old_cycle == NULL
+    if (ngx_process == NGX_PROCESS_WORKER
+        || cycle->old_cycle == NULL
         || cycle->old_cycle->connection_n < cycle->connection_n)
     {
         ngx_test_null(list,
@@ -393,7 +394,8 @@ int ngx_poll_process_events(ngx_cycle_t 
 
         if (event_list[i].fd == -1) {
             /*
-             * the disabled event, a workaround for our possible bug, see below
+             * the disabled event, a workaround for our possible bug,
+             * see the comment below
              */
             continue;
         }
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -9,6 +9,7 @@
 #include <ngx_event.h>
 
 
+
 static int ngx_select_init(ngx_cycle_t *cycle);
 static void ngx_select_done(ngx_cycle_t *cycle);
 static int ngx_select_add_event(ngx_event_t *ev, int event, u_int flags);
@@ -30,10 +31,14 @@ static int            max_write;
 static int            max_fd;
 #endif
 
-static int            nevents;
+static ngx_uint_t     nevents;
 
 static ngx_event_t  **event_index;
+#if 0
 static ngx_event_t  **ready_index;
+#endif
+
+static ngx_event_t   *accept_events;
 
 
 static ngx_str_t    select_name = ngx_string("select");
@@ -77,7 +82,8 @@ static int ngx_select_init(ngx_cycle_t *
         nevents = 0;
     }
 
-    if (cycle->old_cycle == NULL
+    if (ngx_process == NGX_PROCESS_WORKER
+        || cycle->old_cycle == NULL
         || cycle->old_cycle->connection_n < cycle->connection_n)
     {
         ngx_test_null(index,
@@ -91,6 +97,7 @@ static int ngx_select_init(ngx_cycle_t *
         }
         event_index = index;
 
+#if 0
         if (ready_index) {
             ngx_free(ready_index);
         }
@@ -98,6 +105,7 @@ static int ngx_select_init(ngx_cycle_t *
                       ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n,
                       cycle->log),
                       NGX_ERROR);
+#endif
     }
 
     ngx_io = ngx_os_io;
@@ -119,7 +127,9 @@ static int ngx_select_init(ngx_cycle_t *
 static void ngx_select_done(ngx_cycle_t *cycle)
 {
     ngx_free(event_index);
+#if 0
     ngx_free(ready_index);
+#endif
 
     event_index = NULL;
 }
@@ -192,6 +202,9 @@ static int ngx_select_del_event(ngx_even
 
     c = ev->data;
 
+    ev->active = 0;
+    ev->posted = 0;
+
     if (ev->index == NGX_INVALID_INDEX) {
         return NGX_OK;
     }
@@ -230,7 +243,6 @@ static int ngx_select_del_event(ngx_even
         event_index[ev->index]->index = ev->index;
     }
 
-    ev->active = 0;
     ev->index = NGX_INVALID_INDEX;
 
     return NGX_OK;
@@ -239,15 +251,16 @@ static int ngx_select_del_event(ngx_even
 
 static int ngx_select_process_events(ngx_cycle_t *cycle)
 {
-    int                i, ready, nready,found;
-    ngx_err_t          err;
-    ngx_msec_t         timer;
-    ngx_event_t       *ev;
-    ngx_connection_t  *c;
-    ngx_epoch_msec_t   delta;
-    struct timeval     tv, *tp;
+    int                       ready, nready;
+    ngx_uint_t                i, found, lock, expire;
+    ngx_err_t                 err;
+    ngx_msec_t                timer;
+    ngx_event_t              *ev;
+    ngx_connection_t         *c;
+    ngx_epoch_msec_t          delta;
+    struct timeval            tv, *tp;
 #if (HAVE_SELECT_CHANGE_TIMEOUT)
-    static ngx_epoch_msec_t  deltas = 0;
+    static ngx_epoch_msec_t   deltas = 0;
 #endif
 
     work_read_fd_set = master_read_fd_set;
@@ -260,12 +273,24 @@ static int ngx_select_process_events(ngx
         tv.tv_sec = timer / 1000;
         tv.tv_usec = (timer % 1000) * 1000;
         tp = &tv;
+        expire = 1;
 
     } else {
         tp = NULL;
+        expire = 0;
     }
 
+#if (NGX_DEBUG)
+    for (i = 0; i < nevents; i++) {
+        ev = event_index[i];
+        c = ev->data;
+        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                       "select event: fd:%d wr:%d", c->fd,ev->write);
+    }
+#endif
+
 #if !(WIN32)
+
     if (max_fd == -1) {
         for (i = 0; i < nevents; i++) {
             c = event_index[i]->data;
@@ -277,15 +302,18 @@ static int ngx_select_process_events(ngx
         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                        "change max_fd: %d", max_fd);
     }
-#endif
+
+    if (ngx_accept_mutex) {
+        if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
 
-#if (NGX_DEBUG)
-    for (i = 0; i < nevents; i++) {
-        ev = event_index[i];
-        c = ev->data;
-        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                       "select event: fd:%d wr:%d", c->fd,ev->write);
+        if (ngx_accept_mutex_held == 0 && timer > ngx_accept_mutex_delay) {
+            timer = ngx_accept_mutex_delay;
+            expire = 0;
+        }
     }
+
 #endif
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
@@ -372,6 +400,13 @@ static int ngx_select_process_events(ngx
         return NGX_ERROR;
     }
 
+
+    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+        ngx_accept_mutex_unlock();
+        return NGX_ERROR;
+    }
+
+    lock = 1;
     nready = 0;
 
     for (i = 0; i < nevents; i++) {
@@ -395,10 +430,36 @@ static int ngx_select_process_events(ngx
         }
 
         if (found) {
+            ev->ready = 1;
+
+            if (ev->oneshot) {
+                if (ev->timer_set) {
+                    ngx_del_timer(ev);
+                }
+
+                if (ev->write) {
+                    ngx_select_del_event(ev, NGX_WRITE_EVENT, 0);
+                } else {
+                    ngx_select_del_event(ev, NGX_READ_EVENT, 0);
+                }
+            }
+
+            if (ev->accept) {
+                ev->next = accept_events;
+                accept_events = ev;
+            } else {
+                ngx_post_event(ev);
+            }
+
+            nready++;
+
+#if 0
             ready_index[nready++] = ev;
+#endif
         }
     }
 
+#if 0
     for (i = 0; i < nready; i++) {
         ev = ready_index[i];
         ready--;
@@ -423,15 +484,56 @@ static int ngx_select_process_events(ngx
 
         ev->event_handler(ev);
     }
+#endif
 
-    if (ready != 0) {
+    ev = accept_events;
+
+    for ( ;; ) {
+
+        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                      "accept event " PTR_FMT, ev);
+
+        if (ev == NULL) {
+            break;
+        }
+
+        ngx_mutex_unlock(ngx_posted_events_mutex);
+
+        ev->event_handler(ev);
+
+        ev = ev->next;
+
+        if (ev == NULL) {
+            lock = 0;
+            break;
+        }
+
+        if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
+            ngx_accept_mutex_unlock();
+            return NGX_ERROR;
+        }
+
+    }
+
+    if (lock) {
+        ngx_mutex_unlock(ngx_posted_events_mutex);
+    }
+
+    ngx_accept_mutex_unlock();
+    accept_events = NULL;
+
+    if (ready != nready) {
         ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events");
     }
 
-    if (timer && delta) {
+    if (expire && delta) {
         ngx_event_expire_timers((ngx_msec_t) delta);
     }
 
+    if (!ngx_threaded) {
+        ngx_event_process_posted(cycle);
+    }
+
     return NGX_OK;
 }
 
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -12,12 +12,23 @@ typedef struct {
 
     ngx_bufs_t           bufs;
 
+    ngx_uint_t           http_version;
+    ngx_uint_t           proxied;
+
     int                  level;
     int                  wbits;
     int                  memlevel;
 } ngx_http_gzip_conf_t;
 
 
+enum {
+    NGX_HTTP_GZIP_PROXIED_OFF = 0,
+    NGX_HTTP_GZIP_PROXIED_NOCACHABLE,
+    NGX_HTTP_GZIP_PROXIED_POOR_CACHABLE,
+    NGX_HTTP_GZIP_PROXIED_ON
+};
+
+
 typedef struct {
     ngx_chain_t         *in;
     ngx_chain_t         *free;
@@ -76,6 +87,24 @@ static ngx_conf_post_handler_pt  ngx_htt
 
 
 
+static ngx_conf_enum_t  ngx_http_gzip_http_version[] = {
+    { ngx_string("1.0"), NGX_HTTP_VERSION_10 },
+    { ngx_string("1.1"), NGX_HTTP_VERSION_11 },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_conf_enum_t  ngx_http_gzip_proxied[] = {
+    { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF },
+#if 0
+    { ngx_string("nocachable"), NGX_HTTP_GZIP_PROXIED_NOCACHABLE },
+    { ngx_string("poor_cachable"), NGX_HTTP_GZIP_PROXIED_POOR_CACHABLE },
+#endif
+    { ngx_string("on"), NGX_HTTP_GZIP_PROXIED_ON },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_gzip_filter_commands[] = {
 
     { ngx_string("gzip"),
@@ -120,6 +149,20 @@ static ngx_command_t  ngx_http_gzip_filt
       offsetof(ngx_http_gzip_conf_t, no_buffer),
       NULL},
 
+    { ngx_string("gzip_http_version"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, http_version),
+      &ngx_http_gzip_http_version },
+
+    { ngx_string("gzip_proxied"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY,
+      ngx_conf_set_enum_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, proxied),
+      &ngx_http_gzip_proxied },
+
       ngx_null_command
 };
 
@@ -188,7 +231,7 @@ static int ngx_http_gzip_header_filter(n
     if (!conf->enable
         || r->headers_out.status != NGX_HTTP_OK
         || r->header_only
-        /* TODO: conf->http_version */
+        || r->http_version < conf->http_version
         || (r->headers_out.content_encoding
             && r->headers_out.content_encoding->value.len)
         || r->headers_in.accept_encoding == NULL
@@ -206,6 +249,27 @@ static int ngx_http_gzip_header_filter(n
         return ngx_http_next_header_filter(r);
     }
 
+
+    /* TODO: proxied */
+    if (r->headers_in.via && conf->proxied == NGX_HTTP_GZIP_PROXIED_OFF) {
+        return ngx_http_next_header_filter(r);
+    }
+
+
+    /*
+     * if the URL (without the "http://" prefix) is longer than 253 bytes
+     * then MSIE 4.x can not handle the compressed stream - it waits too long,
+     * hangs up or crashes
+     */
+
+    if (r->headers_in.user_agent
+        && r->unparsed_uri.len > 200
+        && ngx_strstr(r->headers_in.user_agent->value.data, "MSIE 4"))
+    {
+        return ngx_http_next_header_filter(r);
+    }
+
+
     ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module,
                         sizeof(ngx_http_gzip_ctx_t), NGX_ERROR);
     ctx->request = r;
@@ -654,6 +718,9 @@ static void *ngx_http_gzip_create_conf(n
 
  /* conf->bufs.num = 0; */
 
+    conf->http_version = NGX_CONF_UNSET_UINT;
+    conf->proxied = NGX_CONF_UNSET_UINT;
+
     conf->level = NGX_CONF_UNSET;
     conf->wbits = NGX_CONF_UNSET;
     conf->memlevel = NGX_CONF_UNSET;
@@ -669,8 +736,15 @@ static char *ngx_http_gzip_merge_conf(ng
     ngx_http_gzip_conf_t *conf = child;
 
     ngx_conf_merge_value(conf->enable, prev->enable, 0);
+
     ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4,
                               /* STUB: PAGE_SIZE */ 4096);
+
+    ngx_conf_merge_unsigned_value(conf->http_version, prev->http_version,
+                                  NGX_HTTP_VERSION_11);
+    ngx_conf_merge_unsigned_value(conf->proxied, prev->proxied,
+                                  NGX_HTTP_GZIP_PROXIED_OFF);
+
     ngx_conf_merge_value(conf->level, prev->level, 1);
     ngx_conf_merge_value(conf->wbits, prev->wbits, MAX_WBITS);
     ngx_conf_merge_value(conf->memlevel, prev->memlevel, MAX_MEM_LEVEL - 1);
--- a/src/http/modules/ngx_http_range_filter.c
+++ b/src/http/modules/ngx_http_range_filter.c
@@ -91,7 +91,10 @@ static ngx_int_t ngx_http_range_header_f
 
         /* STUB: we currently support ranges for file hunks only */
         || !r->sendfile
-        || r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY)
+        || r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY
+
+        || (r->headers_out.content_encoding
+            && r->headers_out.content_encoding->value.len))
     {
         return ngx_http_next_header_filter(r);
     }
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -117,13 +117,19 @@ static ngx_chain_t *ngx_http_proxy_creat
     r = p->request;
     uc = p->lcf->upstream;
 
-    len = http_methods[p->upstream->method - 1].len
-          + uc->uri.len
-          + r->uri.len - uc->location->len
-          + 1 + r->args.len                                  /* 1 is for "?" */
-          + sizeof(http_version) - 1
-          + sizeof(connection_close_header) - 1
-          + 2;                          /* 2 is for "\r\n" at the header end */
+    if (p->upstream->method) {
+        len = http_methods[p->upstream->method - 1].len;
+
+    } else {
+        len = r->method_name.len;
+    }
+
+    len += uc->uri.len
+           + r->uri.len - uc->location->len
+           + 1 + r->args.len                                 /* 1 is for "?" */
+           + sizeof(http_version) - 1
+           + sizeof(connection_close_header) - 1
+           + 2;                         /* 2 is for "\r\n" at the header end */
 
 
     if (p->lcf->preserve_host && r->headers_in.host) {
@@ -179,8 +185,13 @@ static ngx_chain_t *ngx_http_proxy_creat
 
     /* the request line */
 
-    h->last = ngx_cpymem(h->last, http_methods[p->upstream->method - 1].data,
-                         http_methods[p->upstream->method - 1].len);
+    if (p->upstream->method) {
+        h->last = ngx_cpymem(h->last,
+                             http_methods[p->upstream->method - 1].data,
+                             http_methods[p->upstream->method - 1].len);
+    } else {
+        h->last = ngx_cpymem(h->last, r->method_name.data, r->method_name.len);
+    }
 
     h->last = ngx_cpymem(h->last, uc->uri.data, uc->uri.len);
 
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -5,19 +5,17 @@
 
 ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r)
 {
-    u_char  ch, *p;
+    u_char  ch, *p, *m;
     enum {
         sw_start = 0,
-        sw_G,
-        sw_GE,
-        sw_H,
-        sw_HE,
-        sw_HEA,
-        sw_P,
-        sw_PO,
-        sw_POS,
+        sw_method,
         sw_space_after_method,
         sw_spaces_before_uri,
+        sw_schema,
+        sw_schema_slash,
+        sw_schema_slash_slash,
+        sw_host,
+        sw_port,
         sw_after_slash_in_uri,
         sw_check_uri,
         sw_uri,
@@ -48,102 +46,46 @@ ngx_int_t ngx_http_parse_request_line(ng
         case sw_start:
             r->request_start = p - 1;
 
-            switch (ch) {
-            case 'G':
-                state = sw_G;
-                break;
-            case 'H':
-                state = sw_H;
-                break;
-            case 'P':
-                state = sw_P;
-                break;
-            default:
+            if (ch < 'A' || ch > 'Z') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
-            break;
 
-        case sw_G:
-            switch (ch) {
-            case 'E':
-                state = sw_GE;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
-
-        case sw_GE:
-            switch (ch) {
-            case 'T':
-                r->method = NGX_HTTP_GET;
-                state = sw_space_after_method;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
-
-        case sw_H:
-            switch (ch) {
-            case 'E':
-                state = sw_HE;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
+            state = sw_method;
             break;
 
-        case sw_HE:
-            switch (ch) {
-            case 'A':
-                state = sw_HEA;
+        case sw_method:
+            if (ch == ' ') {
+                r->method_end = p - 1;
+                m = r->request_start;
+
+                if (r->method_end - m == 3) {
+
+                    if (*m == 'G' && *(m + 1) == 'E' && *(m + 2) == 'T') {
+                        r->method = NGX_HTTP_GET;
+                    }
+
+                } else if (r->method_end - m == 4) {
+
+                    if (*m == 'P' && *(m + 1) == 'O'
+                        && *(m + 2) == 'T' && *(m + 3) == 'T')
+                    {
+                        r->method = NGX_HTTP_POST;
+
+                    } else if (*m == 'H' && *(m + 1) == 'E'
+                               && *(m + 2) == 'A' && *(m + 3) == 'D')
+                    {
+                        r->method = NGX_HTTP_HEAD;
+                    }
+                }
+
+                state = sw_spaces_before_uri;
                 break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
             }
-            break;
 
-        case sw_HEA:
-            switch (ch) {
-            case 'D':
-                r->method = NGX_HTTP_HEAD;
-                state = sw_space_after_method;
-                break;
-            default:
+            if (ch < 'A' || ch > 'Z') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
-            break;
 
-        case sw_P:
-            switch (ch) {
-            case 'O':
-                state = sw_PO;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
-
-        case sw_PO:
-            switch (ch) {
-            case 'S':
-                state = sw_POS;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
-
-        case sw_POS:
-            switch (ch) {
-            case 'T':
-                r->method = NGX_HTTP_POST;
-                state = sw_space_after_method;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
             break;
 
         /* single space after method */
@@ -167,9 +109,82 @@ ngx_int_t ngx_http_parse_request_line(ng
             case ' ':
                 break;
             default:
-                r->unusual_uri = 1;
+                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
+                    r->schema_start = p - 1;
+                    state = sw_schema;
+                    break;
+                }
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        case sw_schema:
+            switch (ch) {
+            case ':':
+                r->schema_end = p - 1;
+                state = sw_schema_slash;
+                break;
+            default:
+                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
+                    break;
+                }
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        case sw_schema_slash:
+            switch (ch) {
+            case '/':
+                state = sw_schema_slash_slash;
+                break;
+            default:
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        case sw_schema_slash_slash:
+            switch (ch) {
+            case '/':
+                r->host_start = p - 1;
+                state = sw_host;
+                break;
+            default:
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        case sw_host:
+            switch (ch) {
+            case ':':
+                r->host_end = p - 1;
+                state = sw_port;
+                break;
+            case '/':
+                r->host_end = p - 1;
                 r->uri_start = p - 1;
-                state = sw_uri;
+                state = sw_after_slash_in_uri;
+                break;
+            default:
+                if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
+                    || (ch >= '0' && ch <= '9') || ch == '.' || ch == '-')
+                {
+                    break;
+                }
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        case sw_port:
+            switch (ch) {
+            case '/':
+                r->port_end = p - 1;
+                r->uri_start = p - 1;
+                state = sw_after_slash_in_uri;
+                break;
+            default:
+                if (ch < '0' && ch > '9') {
+                    return NGX_HTTP_PARSE_INVALID_REQUEST;
+                }
                 break;
             }
             break;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -337,6 +337,7 @@ static void ngx_http_process_request_lin
 
         /* the request line has been parsed successfully */
 
+#if 0
         /* TODO: we need to handle proxy URIs */
         if (r->unusual_uri) {
             r->request_line.len = r->request_end - r->request_start;
@@ -349,6 +350,7 @@ static void ngx_http_process_request_lin
                                   NGX_HTTP_BAD_REQUEST);
             return;
         }
+#endif
 
         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
@@ -438,6 +440,10 @@ static void ngx_http_process_request_lin
             r->request_line.data[r->request_line.len] = '\0';
         }
 
+        if (r->method == 0) {
+            r->method_name.len = r->method_end - r->request_start + 1;
+            r->method_name.data = r->request_line.data;
+        }
 
         if (r->uri_ext) {
 
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -223,6 +223,8 @@ struct ngx_http_request_s {
     ngx_str_t            exten;
     ngx_str_t            unparsed_uri;
 
+    ngx_str_t            method_name;
+
     ngx_http_request_t  *main;
 
     uint32_t             in_addr;
@@ -246,8 +248,10 @@ struct ngx_http_request_s {
 
     unsigned             http_state:4;
 
+#if 0
     /* URI is not started with '/' - "GET http://" */
     unsigned             unusual_uri:1;
+#endif
     /* URI with "/.", "%" and on Win32 with "//" */
     unsigned             complex_uri:1;
     unsigned             header_timeout_set:1;
@@ -281,6 +285,13 @@ struct ngx_http_request_s {
     u_char              *args_start;
     u_char              *request_start;
     u_char              *request_end;
+    u_char              *method_end;
+    u_char              *schema_start;
+    u_char              *schema_end;
+    u_char              *host_start;
+    u_char              *host_end;
+    u_char              *port_start;
+    u_char              *port_end;
     u_char              *header_name_start;
     u_char              *header_name_end;
     u_char              *header_start;