about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-04-21 11:14:39 -0700
committerEric Wong <normalperson@yhbt.net>2009-04-21 11:16:21 -0700
commited4f50016ab0eab1ebbeac2fe1d0fd8712c7ee91 (patch)
tree5c232a2f34271090ad6512d565ee2f3aee39e7af
parent357fb0a21fdfe6ff3af522a2463248e20b2fa8be (diff)
downloadunicorn-ed4f50016ab0eab1ebbeac2fe1d0fd8712c7ee91.tar.gz
It's part of the HTTP/1.1 (rfc2616), so we might as well
handle it in there and set PATH_INFO while we're at it.

Also, make "OPTIONS *" test not fail Rack::Lint
-rw-r--r--ext/unicorn/http11/http11.c13
-rw-r--r--ext/unicorn/http11/http11_parser.c812
-rw-r--r--ext/unicorn/http11/http11_parser.rl7
-rw-r--r--ext/unicorn/http11/http11_parser_common.rl9
-rw-r--r--lib/unicorn/http_request.rb8
-rw-r--r--test/unit/test_http_parser.rb14
-rw-r--r--test/unit/test_request.rb43
7 files changed, 514 insertions, 392 deletions
diff --git a/ext/unicorn/http11/http11.c b/ext/unicorn/http11/http11.c
index 021c80b..893f710 100644
--- a/ext/unicorn/http11/http11.c
+++ b/ext/unicorn/http11/http11.c
@@ -32,6 +32,7 @@ static VALUE global_query_string;
 static VALUE global_http_version;
 static VALUE global_content_length;
 static VALUE global_request_path;
+static VALUE global_path_info;
 static VALUE global_content_type;
 static VALUE global_server_name;
 static VALUE global_server_port;
@@ -202,6 +203,13 @@ static void request_uri(void *data, const char *at, size_t length)
 
   val = rb_str_new(at, length);
   rb_hash_aset(req, global_request_uri, val);
+
+  /* "OPTIONS * HTTP/1.1\r\n" is a valid request */
+  if (length == 1 && *at == '*') {
+    val = rb_str_new(NULL, 0);
+    rb_hash_aset(req, global_request_path, val);
+    rb_hash_aset(req, global_path_info, val);
+  }
 }
 
 static void fragment(void *data, const char *at, size_t length)
@@ -224,6 +232,10 @@ static void request_path(void *data, const char *at, size_t length)
 
   val = rb_str_new(at, length);
   rb_hash_aset(req, global_request_path, val);
+
+  /* rack says PATH_INFO must start with "/" or be empty */
+  if (!(length == 1 && *at == '*'))
+    rb_hash_aset(req, global_path_info, val);
 }
 
 static void query_string(void *data, const char *at, size_t length)
@@ -390,6 +402,7 @@ void Init_http11()
   DEF_GLOBAL(query_string, "QUERY_STRING");
   DEF_GLOBAL(http_version, "HTTP_VERSION");
   DEF_GLOBAL(request_path, "REQUEST_PATH");
+  DEF_GLOBAL(path_info, "PATH_INFO");
   DEF_GLOBAL(content_length, "CONTENT_LENGTH");
   DEF_GLOBAL(content_type, "CONTENT_TYPE");
   DEF_GLOBAL(server_name, "SERVER_NAME");
diff --git a/ext/unicorn/http11/http11_parser.c b/ext/unicorn/http11/http11_parser.c
index 560fa28..376b2f1 100644
--- a/ext/unicorn/http11/http11_parser.c
+++ b/ext/unicorn/http11/http11_parser.c
@@ -21,6 +21,12 @@ static void snake_upcase_char(char *c)
       *c = '_';
 }
 
+static void downcase_char(char *c)
+{
+  if (*c >= 'A' && *c <= 'Z')
+    *c |= 0x20;
+}
+
 #define LEN(AT, FPC) (FPC - buffer - parser->AT)
 #define MARK(M,FPC) (parser->M = (FPC) - buffer)
 #define PTR_TO(F) (buffer + parser->F)
@@ -28,30 +34,30 @@ static void snake_upcase_char(char *c)
 /** Machine **/
 
 
-#line 85 "http11_parser.rl"
+#line 92 "http11_parser.rl"
 
 
 /** Data **/
 
-#line 37 "http11_parser.c"
+#line 43 "http11_parser.c"
 static const int http_parser_start = 1;
-static const int http_parser_first_final = 57;
+static const int http_parser_first_final = 63;
 static const int http_parser_error = 0;
 
 static const int http_parser_en_main = 1;
 
 
-#line 89 "http11_parser.rl"
+#line 96 "http11_parser.rl"
 
 int http_parser_init(http_parser *parser)  {
   int cs = 0;
-  
-#line 50 "http11_parser.c"
+
+#line 56 "http11_parser.c"
         {
         cs = http_parser_start;
         }
 
-#line 93 "http11_parser.rl"
+#line 100 "http11_parser.rl"
   parser->cs = cs;
   parser->body_start = 0;
   parser->content_len = 0;
@@ -78,8 +84,8 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len)
   assert(*pe == '\0' && "pointer does not end on NUL");
   assert(pe - p == len - off && "pointers aren't same distance");
 
-  
-#line 83 "http11_parser.c"
+
+#line 89 "http11_parser.c"
         {
         if ( p == pe )
                 goto _test_eof;
@@ -103,30 +109,30 @@ st0:
 cs = 0;
         goto _out;
 tr0:
-#line 32 "http11_parser.rl"
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
         goto st2;
 st2:
         if ( ++p == pe )
                 goto _test_eof2;
 case 2:
-#line 114 "http11_parser.c"
+#line 120 "http11_parser.c"
         switch( (*p) ) {
                 case 32: goto tr2;
-                case 36: goto st38;
-                case 95: goto st38;
+                case 36: goto st44;
+                case 95: goto st44;
         }
         if ( (*p) < 48 ) {
                 if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st38;
+                        goto st44;
         } else if ( (*p) > 57 ) {
                 if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st38;
+                        goto st44;
         } else
-                goto st38;
+                goto st44;
         goto st0;
 tr2:
-#line 47 "http11_parser.rl"
+#line 54 "http11_parser.rl"
         {
     if(parser->request_method != NULL)
       parser->request_method(parser->data, PTR_TO(mark), LEN(mark, p));
@@ -136,92 +142,84 @@ st3:
         if ( ++p == pe )
                 goto _test_eof3;
 case 3:
-#line 140 "http11_parser.c"
+#line 146 "http11_parser.c"
         switch( (*p) ) {
                 case 42: goto tr4;
-                case 43: goto tr5;
-                case 47: goto tr6;
-                case 58: goto tr7;
+                case 47: goto tr5;
+                case 72: goto tr6;
+                case 104: goto tr6;
         }
-        if ( (*p) < 65 ) {
-                if ( 45 <= (*p) && (*p) <= 57 )
-                        goto tr5;
-        } else if ( (*p) > 90 ) {
-                if ( 97 <= (*p) && (*p) <= 122 )
-                        goto tr5;
-        } else
-                goto tr5;
         goto st0;
 tr4:
-#line 32 "http11_parser.rl"
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
         goto st4;
 st4:
         if ( ++p == pe )
                 goto _test_eof4;
 case 4:
-#line 164 "http11_parser.c"
+#line 162 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr8;
-                case 35: goto tr9;
+                case 32: goto tr7;
+                case 35: goto tr8;
         }
         goto st0;
-tr8:
-#line 51 "http11_parser.rl"
+tr7:
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st5;
-tr31:
-#line 32 "http11_parser.rl"
+tr30:
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
-#line 55 "http11_parser.rl"
+#line 62 "http11_parser.rl"
         {
     if(parser->fragment != NULL)
       parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st5;
-tr34:
-#line 55 "http11_parser.rl"
+tr33:
+#line 62 "http11_parser.rl"
         {
     if(parser->fragment != NULL)
       parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st5;
-tr42:
-#line 71 "http11_parser.rl"
+tr37:
+#line 78 "http11_parser.rl"
         {
     if(parser->request_path != NULL)
       parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
   }
-#line 51 "http11_parser.rl"
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st5;
-tr53:
-#line 60 "http11_parser.rl"
+tr48:
+#line 67 "http11_parser.rl"
         {MARK(query_start, p); }
-#line 61 "http11_parser.rl"
+#line 68 "http11_parser.rl"
         {
     if(parser->query_string != NULL)
       parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
   }
-#line 51 "http11_parser.rl"
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st5;
-tr57:
-#line 61 "http11_parser.rl"
+tr52:
+#line 68 "http11_parser.rl"
         {
     if(parser->query_string != NULL)
       parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
   }
-#line 51 "http11_parser.rl"
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
@@ -231,19 +229,19 @@ st5:
         if ( ++p == pe )
                 goto _test_eof5;
 case 5:
-#line 235 "http11_parser.c"
+#line 233 "http11_parser.c"
         if ( (*p) == 72 )
-                goto tr10;
+                goto tr9;
         goto st0;
-tr10:
-#line 32 "http11_parser.rl"
+tr9:
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
         goto st6;
 st6:
         if ( ++p == pe )
                 goto _test_eof6;
 case 6:
-#line 247 "http11_parser.c"
+#line 245 "http11_parser.c"
         if ( (*p) == 84 )
                 goto st7;
         goto st0;
@@ -296,29 +294,29 @@ st13:
                 goto _test_eof13;
 case 13:
         if ( (*p) == 13 )
-                goto tr18;
+                goto tr17;
         if ( 48 <= (*p) && (*p) <= 57 )
                 goto st13;
         goto st0;
-tr18:
-#line 66 "http11_parser.rl"
+tr17:
+#line 73 "http11_parser.rl"
         {
     if(parser->http_version != NULL)
       parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st14;
-tr26:
-#line 41 "http11_parser.rl"
+tr25:
+#line 48 "http11_parser.rl"
         { MARK(mark, p); }
-#line 42 "http11_parser.rl"
+#line 49 "http11_parser.rl"
         {
     if(parser->http_field != NULL) {
       parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
     }
   }
         goto st14;
-tr29:
-#line 42 "http11_parser.rl"
+tr28:
+#line 49 "http11_parser.rl"
         {
     if(parser->http_field != NULL) {
       parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
@@ -329,7 +327,7 @@ st14:
         if ( ++p == pe )
                 goto _test_eof14;
 case 14:
-#line 333 "http11_parser.c"
+#line 331 "http11_parser.c"
         if ( (*p) == 10 )
                 goto st15;
         goto st0;
@@ -339,161 +337,161 @@ st15:
 case 15:
         switch( (*p) ) {
                 case 13: goto st16;
-                case 33: goto tr21;
-                case 124: goto tr21;
-                case 126: goto tr21;
+                case 33: goto tr20;
+                case 124: goto tr20;
+                case 126: goto tr20;
         }
         if ( (*p) < 45 ) {
                 if ( (*p) > 39 ) {
                         if ( 42 <= (*p) && (*p) <= 43 )
-                                goto tr21;
+                                goto tr20;
                 } else if ( (*p) >= 35 )
-                        goto tr21;
+                        goto tr20;
         } else if ( (*p) > 46 ) {
                 if ( (*p) < 65 ) {
                         if ( 48 <= (*p) && (*p) <= 57 )
-                                goto tr21;
+                                goto tr20;
                 } else if ( (*p) > 90 ) {
                         if ( 94 <= (*p) && (*p) <= 122 )
-                                goto tr21;
+                                goto tr20;
                 } else
-                        goto tr21;
+                        goto tr20;
         } else
-                goto tr21;
+                goto tr20;
         goto st0;
 st16:
         if ( ++p == pe )
                 goto _test_eof16;
 case 16:
         if ( (*p) == 10 )
-                goto tr22;
+                goto tr21;
         goto st0;
-tr22:
-#line 76 "http11_parser.rl"
+tr21:
+#line 83 "http11_parser.rl"
         {
     parser->body_start = p - buffer + 1;
     if(parser->header_done != NULL)
       parser->header_done(parser->data, p + 1, pe - p - 1);
-    {p++; cs = 57; goto _out;}
+    {p++; cs = 63; goto _out;}
   }
-        goto st57;
-st57:
+        goto st63;
+st63:
         if ( ++p == pe )
-                goto _test_eof57;
-case 57:
-#line 385 "http11_parser.c"
+                goto _test_eof63;
+case 63:
+#line 383 "http11_parser.c"
         goto st0;
-tr21:
-#line 35 "http11_parser.rl"
+tr20:
+#line 41 "http11_parser.rl"
         { MARK(field_start, p); }
-#line 36 "http11_parser.rl"
+#line 42 "http11_parser.rl"
         { snake_upcase_char((char *)p); }
         goto st17;
-tr23:
-#line 36 "http11_parser.rl"
+tr22:
+#line 42 "http11_parser.rl"
         { snake_upcase_char((char *)p); }
         goto st17;
 st17:
         if ( ++p == pe )
                 goto _test_eof17;
 case 17:
-#line 401 "http11_parser.c"
+#line 399 "http11_parser.c"
         switch( (*p) ) {
-                case 33: goto tr23;
-                case 58: goto tr24;
-                case 124: goto tr23;
-                case 126: goto tr23;
+                case 33: goto tr22;
+                case 58: goto tr23;
+                case 124: goto tr22;
+                case 126: goto tr22;
         }
         if ( (*p) < 45 ) {
                 if ( (*p) > 39 ) {
                         if ( 42 <= (*p) && (*p) <= 43 )
-                                goto tr23;
+                                goto tr22;
                 } else if ( (*p) >= 35 )
-                        goto tr23;
+                        goto tr22;
         } else if ( (*p) > 46 ) {
                 if ( (*p) < 65 ) {
                         if ( 48 <= (*p) && (*p) <= 57 )
-                                goto tr23;
+                                goto tr22;
                 } else if ( (*p) > 90 ) {
                         if ( 94 <= (*p) && (*p) <= 122 )
-                                goto tr23;
+                                goto tr22;
                 } else
-                        goto tr23;
+                        goto tr22;
         } else
-                goto tr23;
+                goto tr22;
         goto st0;
-tr24:
-#line 37 "http11_parser.rl"
+tr23:
+#line 44 "http11_parser.rl"
         {
     parser->field_len = LEN(field_start, p);
   }
         goto st18;
-tr27:
-#line 41 "http11_parser.rl"
+tr26:
+#line 48 "http11_parser.rl"
         { MARK(mark, p); }
         goto st18;
 st18:
         if ( ++p == pe )
                 goto _test_eof18;
 case 18:
-#line 440 "http11_parser.c"
+#line 438 "http11_parser.c"
         switch( (*p) ) {
-                case 13: goto tr26;
-                case 32: goto tr27;
+                case 13: goto tr25;
+                case 32: goto tr26;
         }
-        goto tr25;
-tr25:
-#line 41 "http11_parser.rl"
+        goto tr24;
+tr24:
+#line 48 "http11_parser.rl"
         { MARK(mark, p); }
         goto st19;
 st19:
         if ( ++p == pe )
                 goto _test_eof19;
 case 19:
-#line 454 "http11_parser.c"
+#line 452 "http11_parser.c"
         if ( (*p) == 13 )
-                goto tr29;
+                goto tr28;
         goto st19;
-tr9:
-#line 51 "http11_parser.rl"
+tr8:
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st20;
-tr43:
-#line 71 "http11_parser.rl"
+tr38:
+#line 78 "http11_parser.rl"
         {
     if(parser->request_path != NULL)
       parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
   }
-#line 51 "http11_parser.rl"
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st20;
-tr54:
-#line 60 "http11_parser.rl"
+tr49:
+#line 67 "http11_parser.rl"
         {MARK(query_start, p); }
-#line 61 "http11_parser.rl"
+#line 68 "http11_parser.rl"
         {
     if(parser->query_string != NULL)
       parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
   }
-#line 51 "http11_parser.rl"
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
   }
         goto st20;
-tr58:
-#line 61 "http11_parser.rl"
+tr53:
+#line 68 "http11_parser.rl"
         {
     if(parser->query_string != NULL)
       parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
   }
-#line 51 "http11_parser.rl"
+#line 58 "http11_parser.rl"
         {
     if(parser->request_uri != NULL)
       parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
@@ -503,27 +501,27 @@ st20:
         if ( ++p == pe )
                 goto _test_eof20;
 case 20:
-#line 507 "http11_parser.c"
+#line 505 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr31;
+                case 32: goto tr30;
                 case 35: goto st0;
-                case 37: goto tr32;
+                case 37: goto tr31;
                 case 127: goto st0;
         }
         if ( 0 <= (*p) && (*p) <= 31 )
                 goto st0;
-        goto tr30;
-tr30:
-#line 32 "http11_parser.rl"
+        goto tr29;
+tr29:
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
         goto st21;
 st21:
         if ( ++p == pe )
                 goto _test_eof21;
 case 21:
-#line 525 "http11_parser.c"
+#line 523 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr34;
+                case 32: goto tr33;
                 case 35: goto st0;
                 case 37: goto st22;
                 case 127: goto st0;
@@ -531,15 +529,15 @@ case 21:
         if ( 0 <= (*p) && (*p) <= 31 )
                 goto st0;
         goto st21;
-tr32:
-#line 32 "http11_parser.rl"
+tr31:
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
         goto st22;
 st22:
         if ( ++p == pe )
                 goto _test_eof22;
 case 22:
-#line 543 "http11_parser.c"
+#line 541 "http11_parser.c"
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
                         goto st23;
@@ -563,146 +561,147 @@ case 23:
                 goto st21;
         goto st0;
 tr5:
-#line 32 "http11_parser.rl"
+#line 38 "http11_parser.rl"
         {MARK(mark, p); }
         goto st24;
 st24:
         if ( ++p == pe )
                 goto _test_eof24;
 case 24:
-#line 574 "http11_parser.c"
-        switch( (*p) ) {
-                case 43: goto st24;
-                case 58: goto st25;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st24;
-        } else if ( (*p) > 57 ) {
-                if ( (*p) > 90 ) {
-                        if ( 97 <= (*p) && (*p) <= 122 )
-                                goto st24;
-                } else if ( (*p) >= 65 )
-                        goto st24;
-        } else
-                goto st24;
-        goto st0;
-tr7:
-#line 32 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st25;
-st25:
-        if ( ++p == pe )
-                goto _test_eof25;
-case 25:
-#line 599 "http11_parser.c"
+#line 572 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr8;
-                case 35: goto tr9;
-                case 37: goto st26;
+                case 32: goto tr37;
+                case 35: goto tr38;
+                case 37: goto st25;
+                case 59: goto tr40;
+                case 63: goto tr41;
                 case 127: goto st0;
         }
         if ( 0 <= (*p) && (*p) <= 31 )
                 goto st0;
-        goto st25;
-st26:
+        goto st24;
+st25:
         if ( ++p == pe )
-                goto _test_eof26;
-case 26:
+                goto _test_eof25;
+case 25:
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st27;
+                        goto st26;
         } else if ( (*p) > 70 ) {
                 if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st27;
+                        goto st26;
         } else
-                goto st27;
+                goto st26;
         goto st0;
-st27:
+st26:
         if ( ++p == pe )
-                goto _test_eof27;
-case 27:
+                goto _test_eof26;
+case 26:
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st25;
+                        goto st24;
         } else if ( (*p) > 70 ) {
                 if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st25;
+                        goto st24;
         } else
-                goto st25;
+                goto st24;
         goto st0;
-tr6:
-#line 32 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st28;
-st28:
+tr40:
+#line 78 "http11_parser.rl"
+        {
+    if(parser->request_path != NULL)
+      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+  }
+        goto st27;
+st27:
         if ( ++p == pe )
-                goto _test_eof28;
-case 28:
-#line 643 "http11_parser.c"
+                goto _test_eof27;
+case 27:
+#line 621 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr42;
-                case 35: goto tr43;
-                case 37: goto st29;
-                case 59: goto tr45;
-                case 63: goto tr46;
+                case 32: goto tr7;
+                case 35: goto tr8;
+                case 37: goto st28;
+                case 63: goto st30;
                 case 127: goto st0;
         }
         if ( 0 <= (*p) && (*p) <= 31 )
                 goto st0;
-        goto st28;
-st29:
+        goto st27;
+st28:
         if ( ++p == pe )
-                goto _test_eof29;
-case 29:
+                goto _test_eof28;
+case 28:
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st30;
+                        goto st29;
         } else if ( (*p) > 70 ) {
                 if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st30;
+                        goto st29;
         } else
-                goto st30;
+                goto st29;
         goto st0;
-st30:
+st29:
         if ( ++p == pe )
-                goto _test_eof30;
-case 30:
+                goto _test_eof29;
+case 29:
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st28;
+                        goto st27;
         } else if ( (*p) > 70 ) {
                 if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st28;
+                        goto st27;
         } else
-                goto st28;
+                goto st27;
         goto st0;
-tr45:
-#line 71 "http11_parser.rl"
+tr41:
+#line 78 "http11_parser.rl"
         {
     if(parser->request_path != NULL)
       parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
   }
+        goto st30;
+st30:
+        if ( ++p == pe )
+                goto _test_eof30;
+case 30:
+#line 669 "http11_parser.c"
+        switch( (*p) ) {
+                case 32: goto tr48;
+                case 35: goto tr49;
+                case 37: goto tr50;
+                case 127: goto st0;
+        }
+        if ( 0 <= (*p) && (*p) <= 31 )
+                goto st0;
+        goto tr47;
+tr47:
+#line 67 "http11_parser.rl"
+        {MARK(query_start, p); }
         goto st31;
 st31:
         if ( ++p == pe )
                 goto _test_eof31;
 case 31:
-#line 692 "http11_parser.c"
+#line 687 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr8;
-                case 35: goto tr9;
+                case 32: goto tr52;
+                case 35: goto tr53;
                 case 37: goto st32;
-                case 63: goto st34;
                 case 127: goto st0;
         }
         if ( 0 <= (*p) && (*p) <= 31 )
                 goto st0;
         goto st31;
+tr50:
+#line 67 "http11_parser.rl"
+        {MARK(query_start, p); }
+        goto st32;
 st32:
         if ( ++p == pe )
                 goto _test_eof32;
 case 32:
+#line 705 "http11_parser.c"
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
                         goto st33;
@@ -725,126 +724,89 @@ case 33:
         } else
                 goto st31;
         goto st0;
-tr46:
-#line 71 "http11_parser.rl"
-        {
-    if(parser->request_path != NULL)
-      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
-  }
+tr6:
+#line 43 "http11_parser.rl"
+        { downcase_char((char *)p); }
         goto st34;
 st34:
         if ( ++p == pe )
                 goto _test_eof34;
 case 34:
-#line 740 "http11_parser.c"
+#line 736 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr53;
-                case 35: goto tr54;
-                case 37: goto tr55;
-                case 127: goto st0;
+                case 84: goto tr56;
+                case 116: goto tr56;
         }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto tr52;
-tr52:
-#line 60 "http11_parser.rl"
-        {MARK(query_start, p); }
+        goto st0;
+tr56:
+#line 43 "http11_parser.rl"
+        { downcase_char((char *)p); }
         goto st35;
 st35:
         if ( ++p == pe )
                 goto _test_eof35;
 case 35:
-#line 758 "http11_parser.c"
+#line 750 "http11_parser.c"
         switch( (*p) ) {
-                case 32: goto tr57;
-                case 35: goto tr58;
-                case 37: goto st36;
-                case 127: goto st0;
+                case 84: goto tr57;
+                case 116: goto tr57;
         }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto st35;
-tr55:
-#line 60 "http11_parser.rl"
-        {MARK(query_start, p); }
+        goto st0;
+tr57:
+#line 43 "http11_parser.rl"
+        { downcase_char((char *)p); }
         goto st36;
 st36:
         if ( ++p == pe )
                 goto _test_eof36;
 case 36:
-#line 776 "http11_parser.c"
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st37;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st37;
-        } else
-                goto st37;
+#line 764 "http11_parser.c"
+        switch( (*p) ) {
+                case 80: goto tr58;
+                case 112: goto tr58;
+        }
         goto st0;
+tr58:
+#line 43 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st37;
 st37:
         if ( ++p == pe )
                 goto _test_eof37;
 case 37:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st35;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st35;
-        } else
-                goto st35;
+#line 778 "http11_parser.c"
+        switch( (*p) ) {
+                case 58: goto st38;
+                case 83: goto tr60;
+                case 115: goto tr60;
+        }
         goto st0;
 st38:
         if ( ++p == pe )
                 goto _test_eof38;
 case 38:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st39;
-                case 95: goto st39;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st39;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st39;
-        } else
+        if ( (*p) == 47 )
                 goto st39;
         goto st0;
 st39:
         if ( ++p == pe )
                 goto _test_eof39;
 case 39:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st40;
-                case 95: goto st40;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st40;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st40;
-        } else
+        if ( (*p) == 47 )
                 goto st40;
         goto st0;
 st40:
         if ( ++p == pe )
                 goto _test_eof40;
 case 40:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st41;
-                case 95: goto st41;
-        }
         if ( (*p) < 48 ) {
                 if ( 45 <= (*p) && (*p) <= 46 )
                         goto st41;
         } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
+                if ( (*p) > 90 ) {
+                        if ( 97 <= (*p) && (*p) <= 122 )
+                                goto st41;
+                } else if ( (*p) >= 65 )
                         goto st41;
         } else
                 goto st41;
@@ -854,54 +816,38 @@ st41:
                 goto _test_eof41;
 case 41:
         switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st42;
-                case 95: goto st42;
+                case 47: goto tr5;
+                case 58: goto st42;
         }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st42;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st42;
+        if ( (*p) < 65 ) {
+                if ( 45 <= (*p) && (*p) <= 57 )
+                        goto st41;
+        } else if ( (*p) > 90 ) {
+                if ( 97 <= (*p) && (*p) <= 122 )
+                        goto st41;
         } else
-                goto st42;
+                goto st41;
         goto st0;
 st42:
         if ( ++p == pe )
                 goto _test_eof42;
 case 42:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st43;
-                case 95: goto st43;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st43;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st43;
-        } else
-                goto st43;
+        if ( (*p) == 47 )
+                goto tr5;
+        if ( 48 <= (*p) && (*p) <= 57 )
+                goto st42;
         goto st0;
+tr60:
+#line 43 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st43;
 st43:
         if ( ++p == pe )
                 goto _test_eof43;
 case 43:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st44;
-                case 95: goto st44;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st44;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st44;
-        } else
-                goto st44;
+#line 849 "http11_parser.c"
+        if ( (*p) == 58 )
+                goto st38;
         goto st0;
 st44:
         if ( ++p == pe )
@@ -1123,72 +1069,186 @@ st56:
         if ( ++p == pe )
                 goto _test_eof56;
 case 56:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st57;
+                case 95: goto st57;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st57;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st57;
+        } else
+                goto st57;
+        goto st0;
+st57:
+        if ( ++p == pe )
+                goto _test_eof57;
+case 57:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st58;
+                case 95: goto st58;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st58;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st58;
+        } else
+                goto st58;
+        goto st0;
+st58:
+        if ( ++p == pe )
+                goto _test_eof58;
+case 58:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st59;
+                case 95: goto st59;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st59;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st59;
+        } else
+                goto st59;
+        goto st0;
+st59:
+        if ( ++p == pe )
+                goto _test_eof59;
+case 59:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st60;
+                case 95: goto st60;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st60;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st60;
+        } else
+                goto st60;
+        goto st0;
+st60:
+        if ( ++p == pe )
+                goto _test_eof60;
+case 60:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st61;
+                case 95: goto st61;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st61;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st61;
+        } else
+                goto st61;
+        goto st0;
+st61:
+        if ( ++p == pe )
+                goto _test_eof61;
+case 61:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st62;
+                case 95: goto st62;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st62;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st62;
+        } else
+                goto st62;
+        goto st0;
+st62:
+        if ( ++p == pe )
+                goto _test_eof62;
+case 62:
         if ( (*p) == 32 )
                 goto tr2;
         goto st0;
         }
-        _test_eof2: cs = 2; goto _test_eof;
-        _test_eof3: cs = 3; goto _test_eof;
-        _test_eof4: cs = 4; goto _test_eof;
-        _test_eof5: cs = 5; goto _test_eof;
-        _test_eof6: cs = 6; goto _test_eof;
-        _test_eof7: cs = 7; goto _test_eof;
-        _test_eof8: cs = 8; goto _test_eof;
-        _test_eof9: cs = 9; goto _test_eof;
-        _test_eof10: cs = 10; goto _test_eof;
-        _test_eof11: cs = 11; goto _test_eof;
-        _test_eof12: cs = 12; goto _test_eof;
-        _test_eof13: cs = 13; goto _test_eof;
-        _test_eof14: cs = 14; goto _test_eof;
-        _test_eof15: cs = 15; goto _test_eof;
-        _test_eof16: cs = 16; goto _test_eof;
-        _test_eof57: cs = 57; goto _test_eof;
-        _test_eof17: cs = 17; goto _test_eof;
-        _test_eof18: cs = 18; goto _test_eof;
-        _test_eof19: cs = 19; goto _test_eof;
-        _test_eof20: cs = 20; goto _test_eof;
-        _test_eof21: cs = 21; goto _test_eof;
-        _test_eof22: cs = 22; goto _test_eof;
-        _test_eof23: cs = 23; goto _test_eof;
-        _test_eof24: cs = 24; goto _test_eof;
-        _test_eof25: cs = 25; goto _test_eof;
-        _test_eof26: cs = 26; goto _test_eof;
-        _test_eof27: cs = 27; goto _test_eof;
-        _test_eof28: cs = 28; goto _test_eof;
-        _test_eof29: cs = 29; goto _test_eof;
-        _test_eof30: cs = 30; goto _test_eof;
-        _test_eof31: cs = 31; goto _test_eof;
-        _test_eof32: cs = 32; goto _test_eof;
-        _test_eof33: cs = 33; goto _test_eof;
-        _test_eof34: cs = 34; goto _test_eof;
-        _test_eof35: cs = 35; goto _test_eof;
-        _test_eof36: cs = 36; goto _test_eof;
-        _test_eof37: cs = 37; goto _test_eof;
-        _test_eof38: cs = 38; goto _test_eof;
-        _test_eof39: cs = 39; goto _test_eof;
-        _test_eof40: cs = 40; goto _test_eof;
-        _test_eof41: cs = 41; goto _test_eof;
-        _test_eof42: cs = 42; goto _test_eof;
-        _test_eof43: cs = 43; goto _test_eof;
-        _test_eof44: cs = 44; goto _test_eof;
-        _test_eof45: cs = 45; goto _test_eof;
-        _test_eof46: cs = 46; goto _test_eof;
-        _test_eof47: cs = 47; goto _test_eof;
-        _test_eof48: cs = 48; goto _test_eof;
-        _test_eof49: cs = 49; goto _test_eof;
-        _test_eof50: cs = 50; goto _test_eof;
-        _test_eof51: cs = 51; goto _test_eof;
-        _test_eof52: cs = 52; goto _test_eof;
-        _test_eof53: cs = 53; goto _test_eof;
-        _test_eof54: cs = 54; goto _test_eof;
-        _test_eof55: cs = 55; goto _test_eof;
-        _test_eof56: cs = 56; goto _test_eof;
+        _test_eof2: cs = 2; goto _test_eof;
+        _test_eof3: cs = 3; goto _test_eof;
+        _test_eof4: cs = 4; goto _test_eof;
+        _test_eof5: cs = 5; goto _test_eof;
+        _test_eof6: cs = 6; goto _test_eof;
+        _test_eof7: cs = 7; goto _test_eof;
+        _test_eof8: cs = 8; goto _test_eof;
+        _test_eof9: cs = 9; goto _test_eof;
+        _test_eof10: cs = 10; goto _test_eof;
+        _test_eof11: cs = 11; goto _test_eof;
+        _test_eof12: cs = 12; goto _test_eof;
+        _test_eof13: cs = 13; goto _test_eof;
+        _test_eof14: cs = 14; goto _test_eof;
+        _test_eof15: cs = 15; goto _test_eof;
+        _test_eof16: cs = 16; goto _test_eof;
+        _test_eof63: cs = 63; goto _test_eof;
+        _test_eof17: cs = 17; goto _test_eof;
+        _test_eof18: cs = 18; goto _test_eof;
+        _test_eof19: cs = 19; goto _test_eof;
+        _test_eof20: cs = 20; goto _test_eof;
+        _test_eof21: cs = 21; goto _test_eof;
+        _test_eof22: cs = 22; goto _test_eof;
+        _test_eof23: cs = 23; goto _test_eof;
+        _test_eof24: cs = 24; goto _test_eof;
+        _test_eof25: cs = 25; goto _test_eof;
+        _test_eof26: cs = 26; goto _test_eof;
+        _test_eof27: cs = 27; goto _test_eof;
+        _test_eof28: cs = 28; goto _test_eof;
+        _test_eof29: cs = 29; goto _test_eof;
+        _test_eof30: cs = 30; goto _test_eof;
+        _test_eof31: cs = 31; goto _test_eof;
+        _test_eof32: cs = 32; goto _test_eof;
+        _test_eof33: cs = 33; goto _test_eof;
+        _test_eof34: cs = 34; goto _test_eof;
+        _test_eof35: cs = 35; goto _test_eof;
+        _test_eof36: cs = 36; goto _test_eof;
+        _test_eof37: cs = 37; goto _test_eof;
+        _test_eof38: cs = 38; goto _test_eof;
+        _test_eof39: cs = 39; goto _test_eof;
+        _test_eof40: cs = 40; goto _test_eof;
+        _test_eof41: cs = 41; goto _test_eof;
+        _test_eof42: cs = 42; goto _test_eof;
+        _test_eof43: cs = 43; goto _test_eof;
+        _test_eof44: cs = 44; goto _test_eof;
+        _test_eof45: cs = 45; goto _test_eof;
+        _test_eof46: cs = 46; goto _test_eof;
+        _test_eof47: cs = 47; goto _test_eof;
+        _test_eof48: cs = 48; goto _test_eof;
+        _test_eof49: cs = 49; goto _test_eof;
+        _test_eof50: cs = 50; goto _test_eof;
+        _test_eof51: cs = 51; goto _test_eof;
+        _test_eof52: cs = 52; goto _test_eof;
+        _test_eof53: cs = 53; goto _test_eof;
+        _test_eof54: cs = 54; goto _test_eof;
+        _test_eof55: cs = 55; goto _test_eof;
+        _test_eof56: cs = 56; goto _test_eof;
+        _test_eof57: cs = 57; goto _test_eof;
+        _test_eof58: cs = 58; goto _test_eof;
+        _test_eof59: cs = 59; goto _test_eof;
+        _test_eof60: cs = 60; goto _test_eof;
+        _test_eof61: cs = 61; goto _test_eof;
+        _test_eof62: cs = 62; goto _test_eof;
 
         _test_eof: {}
         _out: {}
         }
 
-#line 120 "http11_parser.rl"
+#line 127 "http11_parser.rl"
 
   if (!http_parser_has_error(parser))
     parser->cs = cs;
diff --git a/ext/unicorn/http11/http11_parser.rl b/ext/unicorn/http11/http11_parser.rl
index a86e8cd..a9f7a39 100644
--- a/ext/unicorn/http11/http11_parser.rl
+++ b/ext/unicorn/http11/http11_parser.rl
@@ -19,6 +19,12 @@ static void snake_upcase_char(char *c)
       *c = '_';
 }
 
+static void downcase_char(char *c)
+{
+  if (*c >= 'A' && *c <= 'Z')
+    *c |= 0x20;
+}
+
 #define LEN(AT, FPC) (FPC - buffer - parser->AT)
 #define MARK(M,FPC) (parser->M = (FPC) - buffer)
 #define PTR_TO(F) (buffer + parser->F)
@@ -34,6 +40,7 @@ static void snake_upcase_char(char *c)
 
   action start_field { MARK(field_start, fpc); }
   action snake_upcase_field { snake_upcase_char((char *)fpc); }
+  action downcase_char { downcase_char((char *)fpc); }
   action write_field {
     parser->field_len = LEN(field_start, fpc);
   }
diff --git a/ext/unicorn/http11/http11_parser_common.rl b/ext/unicorn/http11/http11_parser_common.rl
index ee970b1..20fef92 100644
--- a/ext/unicorn/http11/http11_parser_common.rl
+++ b/ext/unicorn/http11/http11_parser_common.rl
@@ -24,8 +24,9 @@
   token = (ascii -- (CTL | tspecials));
 
 # URI schemes and absolute paths
-  scheme = ( alpha | digit | "+" | "-" | "." )* ;
-  absolute_uri = (scheme ":" (uchar | reserved )*);
+  scheme = ( "http"i ("s"i)? ) $downcase_char;
+  hostname = (alnum | "-" | ".")+;
+  host_with_port = (hostname (":" digit*)?);
 
   path = ( pchar+ ( "/" pchar* )* ) ;
   query = ( uchar | reserved )* %query_string ;
@@ -33,8 +34,10 @@
   params = ( param ( ";" param )* ) ;
   rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
   absolute_path = ( "/"+ rel_path );
+  path_uri = absolute_path > mark %request_uri;
+  Absolute_URI = (scheme "://" host_with_port path_uri);
 
-  Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
+  Request_URI = ((absolute_path | "*") >mark %request_uri) | Absolute_URI;
   Fragment = ( uchar | reserved )* >mark %fragment;
   Method = ( upper | digit | safe ){1,20} >mark %request_method;
 
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index a3a1d4d..c9c9503 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -1,5 +1,4 @@
 require 'tempfile'
-require 'uri'
 require 'stringio'
 
 # compiled extension
@@ -129,13 +128,6 @@ module Unicorn
       #  that client may be a proxy, gateway, or other intermediary
       #  acting on behalf of the actual source client."
       @params[Const::REMOTE_ADDR] = socket.unicorn_peeraddr
-
-      # It might be a dumbass full host request header
-      @params[Const::PATH_INFO] = (
-          @params[Const::REQUEST_PATH] ||=
-              URI.parse(@params[Const::REQUEST_URI]).path) or
-         raise "No REQUEST_PATH"
-
       @params[Const::QUERY_STRING] ||= ''
       @params[Const::RACK_INPUT] = @body
       @params.update(DEF_PARAMS)
diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb
index f6fdd47..37a539d 100644
--- a/test/unit/test_http_parser.rb
+++ b/test/unit/test_http_parser.rb
@@ -103,6 +103,20 @@ class HttpParserTest < Test::Unit::TestCase
     assert_nil req['QUERY_STRING']
   end
 
+  def test_absolute_uri
+    parser = HttpParser.new
+    req = {}
+    http = "GET http://example.com/foo?q=bar HTTP/1.0\r\n\r\n"
+    assert parser.execute(req, http)
+    assert_equal 'http', req['rack.url_scheme']
+    assert_equal '/foo?q=bar', req['REQUEST_URI']
+    assert_equal '/foo', req['REQUEST_PATH']
+    assert_equal 'q=bar', req['QUERY_STRING']
+
+    # assert_equal 'example.com', req['HTTP_HOST'] # TODO
+    # assert_equal 'example.com', req['SERVER_NAME'] # TODO
+  end
+
   def test_put_body_oneshot
     parser = HttpParser.new
     req = {}
diff --git a/test/unit/test_request.rb b/test/unit/test_request.rb
index 0613326..dbe4069 100644
--- a/test/unit/test_request.rb
+++ b/test/unit/test_request.rb
@@ -38,23 +38,56 @@ class RequestTest < Test::Unit::TestCase
                              "Host: foo\r\n\r\n")
     res = env = nil
     assert_nothing_raised { env = @request.read(client) }
-    assert_equal '*', env['REQUEST_PATH']
-    assert_equal '*', env['PATH_INFO']
+    assert_equal '', env['REQUEST_PATH']
+    assert_equal '', env['PATH_INFO']
     assert_equal '*', env['REQUEST_URI']
-
-    # assert_nothing_raised { res = @lint.call(env) } # fails Rack lint
+    assert_nothing_raised { res = @lint.call(env) }
   end
 
-  def test_full_url_path
+  def test_absolute_uri_with_query
     client = MockRequest.new("GET http://e:3/x?y=z HTTP/1.1\r\n" \
                              "Host: foo\r\n\r\n")
     res = env = nil
     assert_nothing_raised { env = @request.read(client) }
     assert_equal '/x', env['REQUEST_PATH']
     assert_equal '/x', env['PATH_INFO']
+    assert_equal 'y=z', env['QUERY_STRING']
     assert_nothing_raised { res = @lint.call(env) }
   end
 
+  def test_absolute_uri_with_fragment
+    client = MockRequest.new("GET http://e:3/x#frag HTTP/1.1\r\n" \
+                             "Host: foo\r\n\r\n")
+    res = env = nil
+    assert_nothing_raised { env = @request.read(client) }
+    assert_equal '/x', env['REQUEST_PATH']
+    assert_equal '/x', env['PATH_INFO']
+    assert_equal '', env['QUERY_STRING']
+    assert_equal 'frag', env['FRAGMENT']
+    assert_nothing_raised { res = @lint.call(env) }
+  end
+
+  def test_absolute_uri_with_query_and_fragment
+    client = MockRequest.new("GET http://e:3/x?a=b#frag HTTP/1.1\r\n" \
+                             "Host: foo\r\n\r\n")
+    res = env = nil
+    assert_nothing_raised { env = @request.read(client) }
+    assert_equal '/x', env['REQUEST_PATH']
+    assert_equal '/x', env['PATH_INFO']
+    assert_equal 'a=b', env['QUERY_STRING']
+    assert_equal 'frag', env['FRAGMENT']
+    assert_nothing_raised { res = @lint.call(env) }
+  end
+
+  def test_absolute_uri_unsupported_schemes
+    %w(ssh+http://e/ ftp://e/x http+ssh://e/x).each do |abs_uri|
+      client = MockRequest.new("GET #{abs_uri} HTTP/1.1\r\n" \
+                               "Host: foo\r\n\r\n")
+      assert_raises(HttpParserError) { @request.read(client) }
+      @request.reset
+    end
+  end
+
   def test_x_forwarded_proto_https
     res = env = nil
     client = MockRequest.new("GET / HTTP/1.1\r\n" \