nginx-0.0.3-2004-04-14-09:57:36 import
diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c
index a1640bd..c62a9ea 100644
--- a/src/http/modules/ngx_http_gzip_filter.c
+++ b/src/http/modules/ngx_http_gzip_filter.c
@@ -12,12 +12,23 @@
 
     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_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 @@
       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 @@
     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 @@
         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 @@
 
  /* 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 @@
     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);
diff --git a/src/http/modules/ngx_http_range_filter.c b/src/http/modules/ngx_http_range_filter.c
index 5bf4be0..df32acf 100644
--- a/src/http/modules/ngx_http_range_filter.c
+++ b/src/http/modules/ngx_http_range_filter.c
@@ -91,7 +91,10 @@
 
         /* 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);
     }
diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c
index 760d8d6..41946bf 100644
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -117,13 +117,19 @@
     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 @@
 
     /* 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);
 
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index e1304e8..33bc237 100644
--- 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 @@
         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;
             }
+
+            state = sw_method;
             break;
 
-        case sw_G:
-            switch (ch) {
-            case 'E':
-                state = sw_GE;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
+        case sw_method:
+            if (ch == ' ') {
+                r->method_end = p - 1;
+                m = r->request_start;
 
-        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;
+                if (r->method_end - m == 3) {
 
-        case sw_H:
-            switch (ch) {
-            case 'E':
-                state = sw_HE;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
+                    if (*m == 'G' && *(m + 1) == 'E' && *(m + 2) == 'T') {
+                        r->method = NGX_HTTP_GET;
+                    }
 
-        case sw_HE:
-            switch (ch) {
-            case 'A':
-                state = sw_HEA;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
+                } else if (r->method_end - m == 4) {
 
-        case sw_HEA:
-            switch (ch) {
-            case 'D':
-                r->method = NGX_HTTP_HEAD;
-                state = sw_space_after_method;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
+                    if (*m == 'P' && *(m + 1) == 'O'
+                        && *(m + 2) == 'T' && *(m + 3) == 'T')
+                    {
+                        r->method = NGX_HTTP_POST;
 
-        case sw_P:
-            switch (ch) {
-            case 'O':
-                state = sw_PO;
-                break;
-            default:
-                return NGX_HTTP_PARSE_INVALID_METHOD;
-            }
-            break;
+                    } else if (*m == 'H' && *(m + 1) == 'E'
+                               && *(m + 2) == 'A' && *(m + 3) == 'D')
+                    {
+                        r->method = NGX_HTTP_HEAD;
+                    }
+                }
 
-        case sw_PO:
-            switch (ch) {
-            case 'S':
-                state = sw_POS;
+                state = sw_spaces_before_uri;
                 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:
+            if (ch < 'A' || ch > 'Z') {
                 return NGX_HTTP_PARSE_INVALID_METHOD;
             }
+
             break;
 
         /* single space after method */
@@ -167,9 +109,82 @@
             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;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 976475e..30b3e59 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -337,6 +337,7 @@
 
         /* 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 @@
                                   NGX_HTTP_BAD_REQUEST);
             return;
         }
+#endif
 
         cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
 
@@ -438,6 +440,10 @@
             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) {
 
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 215dedf..e5ae3e1 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -223,6 +223,8 @@
     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 @@
 
     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 @@
     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;