about summary refs log tree commit homepage
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile53
-rw-r--r--Manifest3
-rwxr-xr-xbin/unicorn_rails16
-rw-r--r--ext/unicorn/http11/ext_help.h3
-rw-r--r--ext/unicorn/http11/http11.c117
-rw-r--r--ext/unicorn/http11/http11_parser.c1221
-rw-r--r--ext/unicorn/http11/http11_parser.h1288
-rw-r--r--ext/unicorn/http11/http11_parser.rl134
-rw-r--r--ext/unicorn/http11/http11_parser_common.rl9
-rw-r--r--lib/unicorn.rb27
-rw-r--r--lib/unicorn/configurator.rb3
-rw-r--r--lib/unicorn/const.rb3
-rw-r--r--lib/unicorn/http_request.rb37
-rw-r--r--lib/unicorn/http_response.rb15
-rw-r--r--lib/unicorn/socket_helper.rb (renamed from lib/unicorn/socket.rb)13
-rw-r--r--test/exec/test_exec.rb1
-rw-r--r--test/unit/test_http_parser.rb120
-rw-r--r--test/unit/test_request.rb54
-rw-r--r--test/unit/test_socket_helper.rb45
-rw-r--r--test/unit/test_upload.rb19
20 files changed, 1660 insertions, 1521 deletions
diff --git a/GNUmakefile b/GNUmakefile
index d309cdb..6beed35 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -1,6 +1,8 @@
 # use GNU Make to run tests in parallel, and without depending on Rubygems
 all:: test
 ruby = ruby
+ragel = ragel
+RLFLAGS = -G2
 -include local.mk
 ruby_bin := $(shell which $(ruby))
 ifeq ($(DLEXT),) # "so" for Linux
@@ -14,7 +16,8 @@ endif
 awk_slow := awk '/def test_/{print FILENAME"--"$$2".n"}' 2>/dev/null
 
 rails_vers := $(subst test/rails/app-,,$(wildcard test/rails/app-*))
-slow_tests := test/unit/test_server.rb test/exec/test_exec.rb
+slow_tests := test/unit/test_server.rb test/exec/test_exec.rb \
+  test/unit/test_signals.rb test/unit/test_upload.rb
 log_suffix = .$(RUBY_VERSION).log
 T_r := $(wildcard test/rails/test*.rb)
 T := $(filter-out $(slow_tests) $(T_r), $(wildcard test/*/test*.rb))
@@ -24,32 +27,31 @@ T_n_log := $(subst .n,$(log_suffix),$(T_n))
 T_r_log := $(subst .r,$(log_suffix),$(T_r))
 test_prefix = $(CURDIR)/test/install-$(RUBY_VERSION)
 
-http11_deps := $(addprefix ext/unicorn/http11/, \
-                 ext_help.h http11.c http11_parser.c http11_parser.h \
-                 http11_parser.rl http11_parser_common.rl)
-inst_deps := $(wildcard bin/*) $(wildcard lib/*.rb) \
-  $(wildcard lib/*/*.rb) $(http11_deps)
-
-ext/unicorn/http11/http11_parser.c: ext/unicorn/http11/http11_parser.rl
-        cd $(@D) && ragel $(<F) -C -G2 -o $(@F)
-ext/unicorn/http11/Makefile: ext/unicorn/http11/extconf.rb $(http11_deps)
-        cd $(@D) && $(ruby) $(<F)
-ext/unicorn/http11/http11.$(DLEXT): ext/unicorn/http11/Makefile
+ext := ext/unicorn/http11
+c_files := $(addprefix $(ext)/,ext_help.h http11.c http11_parser.h)
+rl_files := $(addprefix $(ext)/,http11_parser.rl http11_parser_common.rl)
+rb_files := $(shell grep '^\(bin\|lib\)' Manifest)
+inst_deps := $(c_files) $(rb_files)
+
+ragel: $(ext)/http11_parser.h
+$(ext)/http11_parser.h: $(rl_files)
+        cd $(@D) && $(ragel) http11_parser.rl -C $(RLFLAGS) -o $(@F)
+        $(ruby) -i -p -e '$$_.gsub!(%r{[ \t]*$$},"")' $@
+$(ext)/Makefile: $(ext)/extconf.rb $(c_files)
+        cd $(@D) && $(ruby) extconf.rb
+$(ext)/http11.$(DLEXT): $(ext)/Makefile
         $(MAKE) -C $(@D)
-lib/unicorn/http11.$(DLEXT): ext/unicorn/http11/http11.$(DLEXT)
+lib/unicorn/http11.$(DLEXT): $(ext)/http11.$(DLEXT)
         @mkdir -p lib
         install -m644 $< $@
 http11: lib/unicorn/http11.$(DLEXT)
 
-$(test_prefix)/.stamp: install-test
-        > $@
-
-install-test: $(inst_deps)
-        test -n "$(test_prefix)"
+$(test_prefix)/.stamp: $(inst_deps)
         mkdir -p $(test_prefix)/.ccache
-        tar c bin ext lib GNUmakefile | (cd $(test_prefix) && tar x)
+        tar c bin ext lib GNUmakefile Manifest | (cd $(test_prefix) && tar x)
         $(MAKE) -C $(test_prefix) clean
         $(MAKE) -C $(test_prefix) http11 shebang
+        > $@
 
 # this is only intended to be run within $(test_prefix)
 shebang: bin/unicorn bin/unicorn_rails
@@ -106,16 +108,13 @@ install: bin/unicorn bin/unicorn_rails
         $(RM) -r .install-tmp
         $(prep_setup_rb)
 
-clean-http11:
-        -$(MAKE) -C ext/unicorn/http11 clean
-        $(RM) ext/unicorn/http11/Makefile lib/unicorn/http11.$(DLEXT)
-
 setup_rb_files := .config InstalledFiles
-prep_setup_rb := @-$(RM) $(setup_rb_files);$(MAKE) -C ext/unicorn/http11 clean
+prep_setup_rb := @-$(RM) $(setup_rb_files);$(MAKE) -C $(ext) clean
 
-clean: clean-http11
-        $(RM) $(setup_rb_files)
-        $(RM) $(t_log)
+clean:
+        -$(MAKE) -C $(ext) clean
+        $(RM) $(ext)/Makefile lib/unicorn/http11.$(DLEXT)
+        $(RM) $(setup_rb_files) $(t_log)
         $(RM) -r $(test_prefix)
 
 Manifest:
diff --git a/Manifest b/Manifest
index 65832a8..4a9f9cf 100644
--- a/Manifest
+++ b/Manifest
@@ -16,7 +16,6 @@ bin/unicorn_rails
 ext/unicorn/http11/ext_help.h
 ext/unicorn/http11/extconf.rb
 ext/unicorn/http11/http11.c
-ext/unicorn/http11/http11_parser.c
 ext/unicorn/http11/http11_parser.h
 ext/unicorn/http11/http11_parser.rl
 ext/unicorn/http11/http11_parser_common.rl
@@ -30,7 +29,7 @@ lib/unicorn/const.rb
 lib/unicorn/http_request.rb
 lib/unicorn/http_response.rb
 lib/unicorn/launcher.rb
-lib/unicorn/socket.rb
+lib/unicorn/socket_helper.rb
 lib/unicorn/util.rb
 local.mk.sample
 setup.rb
diff --git a/bin/unicorn_rails b/bin/unicorn_rails
index b3c3631..b3fda7b 100755
--- a/bin/unicorn_rails
+++ b/bin/unicorn_rails
@@ -3,8 +3,7 @@ require 'unicorn/launcher'
 require 'optparse'
 require 'fileutils'
 
-rails_pid = File.join(Unicorn::HttpServer::DEFAULT_START_CTX[:cwd],
-                      "/tmp/pids/unicorn.pid")
+rails_pid = "#{Unicorn::HttpServer::START_CTX[:cwd]}/tmp/pids/unicorn.pid"
 cmd = File.basename($0)
 daemonize = false
 listeners = []
@@ -115,10 +114,9 @@ end
 
 require 'pp' if $DEBUG
 
-# Loads Rails and the private version of Rack it bundles. Returns a
-# lambda of arity==0 that will return *another* lambda of arity==1
-# suitable for using inside Rack::Builder.new block.
-rails_loader = lambda do ||
+# this won't run until after forking if preload_app is false
+app = lambda do ||
+  # Load Rails and the private version of Rack it bundles.
   begin
     require 'config/boot'
   rescue LoadError => err
@@ -129,7 +127,7 @@ rails_loader = lambda do ||
   defined?(::Rails::VERSION::STRING) or
     abort "Rails::VERSION::STRING not defined by config/boot"
 
-  case config
+  inner_app = case config
   when nil
     require 'config/environment'
 
@@ -155,12 +153,8 @@ rails_loader = lambda do ||
     require config
     Object.const_get(File.basename(config, '.rb').capitalize)
   end
-end
 
-# this won't run until after forking if preload_app is false
-app = lambda do ||
   map_path ||= '/'
-  inner_app = rails_loader.call
   Rack::Builder.new do
     if inner_app.class.to_s == "Unicorn::App::OldRails"
       if map_path != '/'
diff --git a/ext/unicorn/http11/ext_help.h b/ext/unicorn/http11/ext_help.h
index 08c0e1e..17f7b01 100644
--- a/ext/unicorn/http11/ext_help.h
+++ b/ext/unicorn/http11/ext_help.h
@@ -1,9 +1,6 @@
 #ifndef ext_help_h
 #define ext_help_h
 
-#define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be.");
-#define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name);
-#define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T);
 #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
 
 #ifdef DEBUG
diff --git a/ext/unicorn/http11/http11.c b/ext/unicorn/http11/http11.c
index 021c80b..cd7a8f7 100644
--- a/ext/unicorn/http11/http11.c
+++ b/ext/unicorn/http11/http11.c
@@ -9,6 +9,16 @@
 #include <string.h>
 #include "http11_parser.h"
 
+static http_parser *data_get(VALUE self)
+{
+  http_parser *http;
+
+  Data_Get_Struct(self, http_parser, http);
+  if (!http)
+    rb_raise(rb_eArgError, "NULL found for http when shouldn't be.");
+  return http;
+}
+
 #ifndef RSTRING_PTR
 #define RSTRING_PTR(s) (RSTRING(s)->ptr)
 #endif
@@ -30,9 +40,8 @@ static VALUE global_request_uri;
 static VALUE global_fragment;
 static VALUE global_query_string;
 static VALUE global_http_version;
-static VALUE global_content_length;
 static VALUE global_request_path;
-static VALUE global_content_type;
+static VALUE global_path_info;
 static VALUE global_server_name;
 static VALUE global_server_port;
 static VALUE global_server_protocol;
@@ -45,14 +54,25 @@ static VALUE global_localhost;
 static VALUE global_http;
 
 /** Defines common length and error messages for input length validation. */
-#define DEF_MAX_LENGTH(N,length) const size_t MAX_##N##_LENGTH = length; const char *MAX_##N##_LENGTH_ERR = "HTTP element " # N  " is longer than the " # length " allowed length."
+#define DEF_MAX_LENGTH(N, length) \
+  static const size_t MAX_##N##_LENGTH = length; \
+  static const char * const MAX_##N##_LENGTH_ERR = \
+    "HTTP element " # N  " is longer than the " # length " allowed length."
 
-/** Validates the max length of given input and throws an HttpParserError exception if over. */
-#define VALIDATE_MAX_LENGTH(len, N) if(len > MAX_##N##_LENGTH) { rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); }
+/**
+ * Validates the max length of given input and throws an HttpParserError
+ * exception if over.
+ */
+#define VALIDATE_MAX_LENGTH(len, N) do { \
+  if (len > MAX_##N##_LENGTH) \
+    rb_raise(eHttpParserError, MAX_##N##_LENGTH_ERR); \
+} while (0)
 
 /** Defines global strings in the init method. */
-#define DEF_GLOBAL(N, val)   global_##N = rb_obj_freeze(rb_str_new2(val)); rb_global_variable(&global_##N)
-
+#define DEF_GLOBAL(N, val) do { \
+  global_##N = rb_obj_freeze(rb_str_new(val, sizeof(val) - 1)); \
+  rb_global_variable(&global_##N); \
+} while (0)
 
 /* Defines the maximum allowed lengths for various input elements.*/
 DEF_MAX_LENGTH(FIELD_NAME, 256);
@@ -153,14 +173,11 @@ static void http_field(void *data, const char *field,
                        size_t flen, const char *value, size_t vlen)
 {
   VALUE req = (VALUE)data;
-  VALUE v = Qnil;
   VALUE f = Qnil;
 
   VALIDATE_MAX_LENGTH(flen, FIELD_NAME);
   VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE);
 
-  v = rb_str_new(value, vlen);
-
   f = find_common_field_value(field, flen);
 
   if (f == Qnil) {
@@ -179,9 +196,11 @@ static void http_field(void *data, const char *field,
     memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen);
     assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0'); /* paranoia */
     /* fprintf(stderr, "UNKNOWN HEADER <%s>\n", RSTRING_PTR(f)); */
+  } else if (f == global_http_host && rb_hash_aref(req, f) != Qnil) {
+    return;
   }
 
-  rb_hash_aset(req, f, v);
+  rb_hash_aset(req, f, rb_str_new(value, vlen));
 }
 
 static void request_method(void *data, const char *at, size_t length)
@@ -193,6 +212,16 @@ static void request_method(void *data, const char *at, size_t length)
   rb_hash_aset(req, global_request_method, val);
 }
 
+static void scheme(void *data, const char *at, size_t length)
+{
+  rb_hash_aset((VALUE)data, global_rack_url_scheme, rb_str_new(at, length));
+}
+
+static void host(void *data, const char *at, size_t length)
+{
+  rb_hash_aset((VALUE)data, global_http_host, rb_str_new(at, length));
+}
+
 static void request_uri(void *data, const char *at, size_t length)
 {
   VALUE req = (VALUE)data;
@@ -202,6 +231,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 +260,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)
@@ -252,22 +292,32 @@ static void header_done(void *data, const char *at, size_t length)
   VALUE server_port = global_port_80;
   VALUE temp;
 
+  /* rack requires QUERY_STRING */
+  if (rb_hash_aref(req, global_query_string) == Qnil)
+    rb_hash_aset(req, global_query_string, rb_str_new(NULL, 0));
+
   /* set rack.url_scheme to "https" or "http", no others are allowed by Rack */
-  if ((temp = rb_hash_aref(req, global_http_x_forwarded_proto)) != Qnil &&
-      RSTRING_LEN(temp) == 5 &&
-      !memcmp("https", RSTRING_PTR(temp), 5))
+  if ((temp = rb_hash_aref(req, global_rack_url_scheme)) == Qnil) {
+    if ((temp = rb_hash_aref(req, global_http_x_forwarded_proto)) != Qnil &&
+        RSTRING_LEN(temp) == 5 &&
+        !memcmp("https", RSTRING_PTR(temp), 5))
+      server_port = global_port_443;
+    else
+      temp = global_http;
+    rb_hash_aset(req, global_rack_url_scheme, temp);
+  } else if (RSTRING_LEN(temp) == 5 && !memcmp("https", RSTRING_PTR(temp), 5)) {
     server_port = global_port_443;
-  else
-    temp = global_http;
-  rb_hash_aset(req, global_rack_url_scheme, temp);
+  }
 
   /* parse and set the SERVER_NAME and SERVER_PORT variables */
   if ((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
     char *colon = memchr(RSTRING_PTR(temp), ':', RSTRING_LEN(temp));
     if (colon) {
+      long port_start = colon - RSTRING_PTR(temp) + 1;
+
       server_name = rb_str_substr(temp, 0, colon - RSTRING_PTR(temp));
-      server_port = rb_str_substr(temp, colon - RSTRING_PTR(temp)+1,
-                                  RSTRING_LEN(temp));
+      if ((RSTRING_LEN(temp) - port_start) > 0)
+        server_port = rb_str_substr(temp, port_start, RSTRING_LEN(temp));
     } else {
       server_name = temp;
     }
@@ -294,14 +344,6 @@ static VALUE HttpParser_alloc(VALUE klass)
   VALUE obj;
   http_parser *hp = ALLOC_N(http_parser, 1);
   TRACE();
-  hp->http_field = http_field;
-  hp->request_method = request_method;
-  hp->request_uri = request_uri;
-  hp->fragment = fragment;
-  hp->request_path = request_path;
-  hp->query_string = query_string;
-  hp->http_version = http_version;
-  hp->header_done = header_done;
   http_parser_init(hp);
 
   obj = Data_Wrap_Struct(klass, NULL, HttpParser_free, hp);
@@ -318,9 +360,7 @@ static VALUE HttpParser_alloc(VALUE klass)
  */
 static VALUE HttpParser_init(VALUE self)
 {
-  http_parser *http = NULL;
-  DATA_GET(self, http_parser, http);
-  http_parser_init(http);
+  http_parser_init(data_get(self));
 
   return self;
 }
@@ -335,9 +375,7 @@ static VALUE HttpParser_init(VALUE self)
  */
 static VALUE HttpParser_reset(VALUE self)
 {
-  http_parser *http = NULL;
-  DATA_GET(self, http_parser, http);
-  http_parser_init(http);
+  http_parser_init(data_get(self));
 
   return Qnil;
 }
@@ -358,12 +396,10 @@ static VALUE HttpParser_reset(VALUE self)
 
 static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data)
 {
-  http_parser *http;
+  http_parser *http = data_get(self);
   char *dptr = RSTRING_PTR(data);
   long dlen = RSTRING_LEN(data);
 
-  DATA_GET(self, http_parser, http);
-
   if (http->nread < dlen) {
     http->data = (void *)req_hash;
     http_parser_execute(http, dptr, dlen);
@@ -378,9 +414,8 @@ static VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data)
   rb_raise(eHttpParserError, "Requested start is after data buffer end.");
 }
 
-void Init_http11()
+void Init_http11(void)
 {
-
   mUnicorn = rb_define_module("Unicorn");
 
   DEF_GLOBAL(rack_url_scheme, "rack.url_scheme");
@@ -390,13 +425,11 @@ void Init_http11()
   DEF_GLOBAL(query_string, "QUERY_STRING");
   DEF_GLOBAL(http_version, "HTTP_VERSION");
   DEF_GLOBAL(request_path, "REQUEST_PATH");
-  DEF_GLOBAL(content_length, "CONTENT_LENGTH");
-  DEF_GLOBAL(content_type, "CONTENT_TYPE");
+  DEF_GLOBAL(path_info, "PATH_INFO");
   DEF_GLOBAL(server_name, "SERVER_NAME");
   DEF_GLOBAL(server_port, "SERVER_PORT");
   DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL");
   DEF_GLOBAL(server_protocol_value, "HTTP/1.1");
-  DEF_GLOBAL(http_host, "HTTP_HOST");
   DEF_GLOBAL(http_x_forwarded_proto, "HTTP_X_FORWARDED_PROTO");
   DEF_GLOBAL(port_80, "80");
   DEF_GLOBAL(port_443, "443");
@@ -412,4 +445,6 @@ void Init_http11()
   rb_define_method(cHttpParser, "execute", HttpParser_execute,2);
   sym_http_body = ID2SYM(rb_intern("http_body"));
   init_common_fields();
+  global_http_host = find_common_field_value("HOST", 4);
+  assert(global_http_host != Qnil);
 }
diff --git a/ext/unicorn/http11/http11_parser.c b/ext/unicorn/http11/http11_parser.c
deleted file mode 100644
index b6d55c8..0000000
--- a/ext/unicorn/http11/http11_parser.c
+++ /dev/null
@@ -1,1221 +0,0 @@
-#line 1 "http11_parser.rl"
-/**
- * Copyright (c) 2005 Zed A. Shaw
- * You can redistribute it and/or modify it under the same terms as Ruby.
- */
-#include "http11_parser.h"
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-
-/*
- * capitalizes all lower-case ASCII characters,
- * converts dashes to underscores.
- */
-static void snake_upcase_char(char *c)
-{
-    if (*c >= 'a' && *c <= 'z')
-      *c &= ~0x20;
-    else if (*c == '-')
-      *c = '_';
-}
-
-#define LEN(AT, FPC) (FPC - buffer - parser->AT)
-#define MARK(M,FPC) (parser->M = (FPC) - buffer)
-#define PTR_TO(F) (buffer + parser->F)
-
-/** Machine **/
-
-#line 87 "http11_parser.rl"
-
-
-/** Data **/
-
-#line 37 "http11_parser.c"
-static const int http_parser_start = 1;
-static const int http_parser_first_final = 57;
-static const int http_parser_error = 0;
-
-static const int http_parser_en_main = 1;
-
-#line 91 "http11_parser.rl"
-
-int http_parser_init(http_parser *parser)  {
-  int cs = 0;
-  
-#line 49 "http11_parser.c"
-        {
-        cs = http_parser_start;
-        }
-#line 95 "http11_parser.rl"
-  parser->cs = cs;
-  parser->body_start = 0;
-  parser->content_len = 0;
-  parser->mark = 0;
-  parser->nread = 0;
-  parser->field_len = 0;
-  parser->field_start = 0;    
-
-  return(1);
-}
-
-
-/** exec **/
-size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len)  {
-  const char *p, *pe;
-  int cs = parser->cs;
-  size_t off = parser->nread;
-
-  assert(off <= len && "offset past end of buffer");
-
-  p = buffer+off;
-  pe = buffer+len;
-
-  assert(*pe == '\0' && "pointer does not end on NUL");
-  assert(pe - p == len - off && "pointers aren't same distance");
-
-  
-#line 81 "http11_parser.c"
-        {
-        if ( p == pe )
-                goto _test_eof;
-        switch ( cs )
-        {
-case 1:
-        switch( (*p) ) {
-                case 36: goto tr0;
-                case 95: goto tr0;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto tr0;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto tr0;
-        } else
-                goto tr0;
-        goto st0;
-st0:
-cs = 0;
-        goto _out;
-tr0:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st2;
-st2:
-        if ( ++p == pe )
-                goto _test_eof2;
-case 2:
-#line 112 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st38;
-                case 95: goto st38;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st38;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st38;
-        } else
-                goto st38;
-        goto st0;
-tr2:
-#line 49 "http11_parser.rl"
-        {
-    if(parser->request_method != NULL)
-      parser->request_method(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st3;
-st3:
-        if ( ++p == pe )
-                goto _test_eof3;
-case 3:
-#line 138 "http11_parser.c"
-        switch( (*p) ) {
-                case 42: goto tr4;
-                case 43: goto tr5;
-                case 47: goto tr6;
-                case 58: goto tr7;
-        }
-        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 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st4;
-st4:
-        if ( ++p == pe )
-                goto _test_eof4;
-case 4:
-#line 162 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr8;
-                case 35: goto tr9;
-        }
-        goto st0;
-tr8:
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st5;
-tr31:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-#line 57 "http11_parser.rl"
-        {
-    if(parser->fragment != NULL)
-      parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st5;
-tr34:
-#line 57 "http11_parser.rl"
-        {
-    if(parser->fragment != NULL)
-      parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st5;
-tr42:
-#line 73 "http11_parser.rl"
-        {
-    if(parser->request_path != NULL)
-      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
-  }
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st5;
-tr53:
-#line 62 "http11_parser.rl"
-        {MARK(query_start, p); }
-#line 63 "http11_parser.rl"
-        {
-    if(parser->query_string != NULL)
-      parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
-  }
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st5;
-tr57:
-#line 63 "http11_parser.rl"
-        {
-    if(parser->query_string != NULL)
-      parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
-  }
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st5;
-st5:
-        if ( ++p == pe )
-                goto _test_eof5;
-case 5:
-#line 233 "http11_parser.c"
-        if ( (*p) == 72 )
-                goto tr10;
-        goto st0;
-tr10:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st6;
-st6:
-        if ( ++p == pe )
-                goto _test_eof6;
-case 6:
-#line 245 "http11_parser.c"
-        if ( (*p) == 84 )
-                goto st7;
-        goto st0;
-st7:
-        if ( ++p == pe )
-                goto _test_eof7;
-case 7:
-        if ( (*p) == 84 )
-                goto st8;
-        goto st0;
-st8:
-        if ( ++p == pe )
-                goto _test_eof8;
-case 8:
-        if ( (*p) == 80 )
-                goto st9;
-        goto st0;
-st9:
-        if ( ++p == pe )
-                goto _test_eof9;
-case 9:
-        if ( (*p) == 47 )
-                goto st10;
-        goto st0;
-st10:
-        if ( ++p == pe )
-                goto _test_eof10;
-case 10:
-        if ( 48 <= (*p) && (*p) <= 57 )
-                goto st11;
-        goto st0;
-st11:
-        if ( ++p == pe )
-                goto _test_eof11;
-case 11:
-        if ( (*p) == 46 )
-                goto st12;
-        if ( 48 <= (*p) && (*p) <= 57 )
-                goto st11;
-        goto st0;
-st12:
-        if ( ++p == pe )
-                goto _test_eof12;
-case 12:
-        if ( 48 <= (*p) && (*p) <= 57 )
-                goto st13;
-        goto st0;
-st13:
-        if ( ++p == pe )
-                goto _test_eof13;
-case 13:
-        if ( (*p) == 13 )
-                goto tr18;
-        if ( 48 <= (*p) && (*p) <= 57 )
-                goto st13;
-        goto st0;
-tr18:
-#line 68 "http11_parser.rl"
-        {        
-    if(parser->http_version != NULL)
-      parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st14;
-tr26:
-#line 43 "http11_parser.rl"
-        { MARK(mark, p); }
-#line 44 "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 44 "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;
-st14:
-        if ( ++p == pe )
-                goto _test_eof14;
-case 14:
-#line 331 "http11_parser.c"
-        if ( (*p) == 10 )
-                goto st15;
-        goto st0;
-st15:
-        if ( ++p == pe )
-                goto _test_eof15;
-case 15:
-        switch( (*p) ) {
-                case 13: goto st16;
-                case 33: goto tr21;
-                case 124: goto tr21;
-                case 126: goto tr21;
-        }
-        if ( (*p) < 45 ) {
-                if ( (*p) > 39 ) {
-                        if ( 42 <= (*p) && (*p) <= 43 )
-                                goto tr21;
-                } else if ( (*p) >= 35 )
-                        goto tr21;
-        } else if ( (*p) > 46 ) {
-                if ( (*p) < 65 ) {
-                        if ( 48 <= (*p) && (*p) <= 57 )
-                                goto tr21;
-                } else if ( (*p) > 90 ) {
-                        if ( 94 <= (*p) && (*p) <= 122 )
-                                goto tr21;
-                } else
-                        goto tr21;
-        } else
-                goto tr21;
-        goto st0;
-st16:
-        if ( ++p == pe )
-                goto _test_eof16;
-case 16:
-        if ( (*p) == 10 )
-                goto tr22;
-        goto st0;
-tr22:
-#line 78 "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;}
-  }
-        goto st57;
-st57:
-        if ( ++p == pe )
-                goto _test_eof57;
-case 57:
-#line 383 "http11_parser.c"
-        goto st0;
-tr21:
-#line 37 "http11_parser.rl"
-        { MARK(field_start, p); }
-#line 38 "http11_parser.rl"
-        { snake_upcase_char((char *)p); }
-        goto st17;
-tr23:
-#line 38 "http11_parser.rl"
-        { snake_upcase_char((char *)p); }
-        goto st17;
-st17:
-        if ( ++p == pe )
-                goto _test_eof17;
-case 17:
-#line 399 "http11_parser.c"
-        switch( (*p) ) {
-                case 33: goto tr23;
-                case 58: goto tr24;
-                case 124: goto tr23;
-                case 126: goto tr23;
-        }
-        if ( (*p) < 45 ) {
-                if ( (*p) > 39 ) {
-                        if ( 42 <= (*p) && (*p) <= 43 )
-                                goto tr23;
-                } else if ( (*p) >= 35 )
-                        goto tr23;
-        } else if ( (*p) > 46 ) {
-                if ( (*p) < 65 ) {
-                        if ( 48 <= (*p) && (*p) <= 57 )
-                                goto tr23;
-                } else if ( (*p) > 90 ) {
-                        if ( 94 <= (*p) && (*p) <= 122 )
-                                goto tr23;
-                } else
-                        goto tr23;
-        } else
-                goto tr23;
-        goto st0;
-tr24:
-#line 39 "http11_parser.rl"
-        {
-    parser->field_len = LEN(field_start, p);
-  }
-        goto st18;
-tr27:
-#line 43 "http11_parser.rl"
-        { MARK(mark, p); }
-        goto st18;
-st18:
-        if ( ++p == pe )
-                goto _test_eof18;
-case 18:
-#line 438 "http11_parser.c"
-        switch( (*p) ) {
-                case 13: goto tr26;
-                case 32: goto tr27;
-        }
-        goto tr25;
-tr25:
-#line 43 "http11_parser.rl"
-        { MARK(mark, p); }
-        goto st19;
-st19:
-        if ( ++p == pe )
-                goto _test_eof19;
-case 19:
-#line 452 "http11_parser.c"
-        if ( (*p) == 13 )
-                goto tr29;
-        goto st19;
-tr9:
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st20;
-tr43:
-#line 73 "http11_parser.rl"
-        {
-    if(parser->request_path != NULL)
-      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
-  }
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st20;
-tr54:
-#line 62 "http11_parser.rl"
-        {MARK(query_start, p); }
-#line 63 "http11_parser.rl"
-        {
-    if(parser->query_string != NULL)
-      parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
-  }
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st20;
-tr58:
-#line 63 "http11_parser.rl"
-        {
-    if(parser->query_string != NULL)
-      parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
-  }
-#line 53 "http11_parser.rl"
-        {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
-  }
-        goto st20;
-st20:
-        if ( ++p == pe )
-                goto _test_eof20;
-case 20:
-#line 505 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr31;
-                case 35: goto st0;
-                case 37: goto tr32;
-                case 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto tr30;
-tr30:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st21;
-st21:
-        if ( ++p == pe )
-                goto _test_eof21;
-case 21:
-#line 523 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr34;
-                case 35: goto st0;
-                case 37: goto st22;
-                case 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto st21;
-tr32:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st22;
-st22:
-        if ( ++p == pe )
-                goto _test_eof22;
-case 22:
-#line 541 "http11_parser.c"
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st23;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st23;
-        } else
-                goto st23;
-        goto st0;
-st23:
-        if ( ++p == pe )
-                goto _test_eof23;
-case 23:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st21;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st21;
-        } else
-                goto st21;
-        goto st0;
-tr5:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st24;
-st24:
-        if ( ++p == pe )
-                goto _test_eof24;
-case 24:
-#line 572 "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 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st25;
-st25:
-        if ( ++p == pe )
-                goto _test_eof25;
-case 25:
-#line 597 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr8;
-                case 35: goto tr9;
-                case 37: goto st26;
-                case 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto st25;
-st26:
-        if ( ++p == pe )
-                goto _test_eof26;
-case 26:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st27;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st27;
-        } else
-                goto st27;
-        goto st0;
-st27:
-        if ( ++p == pe )
-                goto _test_eof27;
-case 27:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st25;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st25;
-        } else
-                goto st25;
-        goto st0;
-tr6:
-#line 34 "http11_parser.rl"
-        {MARK(mark, p); }
-        goto st28;
-st28:
-        if ( ++p == pe )
-                goto _test_eof28;
-case 28:
-#line 641 "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 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto st28;
-st29:
-        if ( ++p == pe )
-                goto _test_eof29;
-case 29:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st30;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st30;
-        } else
-                goto st30;
-        goto st0;
-st30:
-        if ( ++p == pe )
-                goto _test_eof30;
-case 30:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st28;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st28;
-        } else
-                goto st28;
-        goto st0;
-tr45:
-#line 73 "http11_parser.rl"
-        {
-    if(parser->request_path != NULL)
-      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
-  }
-        goto st31;
-st31:
-        if ( ++p == pe )
-                goto _test_eof31;
-case 31:
-#line 690 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr8;
-                case 35: goto tr9;
-                case 37: goto st32;
-                case 63: goto st34;
-                case 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto st31;
-st32:
-        if ( ++p == pe )
-                goto _test_eof32;
-case 32:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st33;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st33;
-        } else
-                goto st33;
-        goto st0;
-st33:
-        if ( ++p == pe )
-                goto _test_eof33;
-case 33:
-        if ( (*p) < 65 ) {
-                if ( 48 <= (*p) && (*p) <= 57 )
-                        goto st31;
-        } else if ( (*p) > 70 ) {
-                if ( 97 <= (*p) && (*p) <= 102 )
-                        goto st31;
-        } else
-                goto st31;
-        goto st0;
-tr46:
-#line 73 "http11_parser.rl"
-        {
-    if(parser->request_path != NULL)
-      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p));
-  }
-        goto st34;
-st34:
-        if ( ++p == pe )
-                goto _test_eof34;
-case 34:
-#line 738 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr53;
-                case 35: goto tr54;
-                case 37: goto tr55;
-                case 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto tr52;
-tr52:
-#line 62 "http11_parser.rl"
-        {MARK(query_start, p); }
-        goto st35;
-st35:
-        if ( ++p == pe )
-                goto _test_eof35;
-case 35:
-#line 756 "http11_parser.c"
-        switch( (*p) ) {
-                case 32: goto tr57;
-                case 35: goto tr58;
-                case 37: goto st36;
-                case 127: goto st0;
-        }
-        if ( 0 <= (*p) && (*p) <= 31 )
-                goto st0;
-        goto st35;
-tr55:
-#line 62 "http11_parser.rl"
-        {MARK(query_start, p); }
-        goto st36;
-st36:
-        if ( ++p == pe )
-                goto _test_eof36;
-case 36:
-#line 774 "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;
-        goto st0;
-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;
-        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
-                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
-                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 )
-                        goto st41;
-        } else
-                goto st41;
-        goto st0;
-st41:
-        if ( ++p == pe )
-                goto _test_eof41;
-case 41:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st42;
-                case 95: goto st42;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st42;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st42;
-        } else
-                goto st42;
-        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;
-        goto st0;
-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;
-        goto st0;
-st44:
-        if ( ++p == pe )
-                goto _test_eof44;
-case 44:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st45;
-                case 95: goto st45;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st45;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st45;
-        } else
-                goto st45;
-        goto st0;
-st45:
-        if ( ++p == pe )
-                goto _test_eof45;
-case 45:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st46;
-                case 95: goto st46;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st46;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st46;
-        } else
-                goto st46;
-        goto st0;
-st46:
-        if ( ++p == pe )
-                goto _test_eof46;
-case 46:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st47;
-                case 95: goto st47;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st47;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st47;
-        } else
-                goto st47;
-        goto st0;
-st47:
-        if ( ++p == pe )
-                goto _test_eof47;
-case 47:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st48;
-                case 95: goto st48;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st48;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st48;
-        } else
-                goto st48;
-        goto st0;
-st48:
-        if ( ++p == pe )
-                goto _test_eof48;
-case 48:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st49;
-                case 95: goto st49;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st49;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st49;
-        } else
-                goto st49;
-        goto st0;
-st49:
-        if ( ++p == pe )
-                goto _test_eof49;
-case 49:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st50;
-                case 95: goto st50;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st50;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st50;
-        } else
-                goto st50;
-        goto st0;
-st50:
-        if ( ++p == pe )
-                goto _test_eof50;
-case 50:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st51;
-                case 95: goto st51;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st51;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st51;
-        } else
-                goto st51;
-        goto st0;
-st51:
-        if ( ++p == pe )
-                goto _test_eof51;
-case 51:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st52;
-                case 95: goto st52;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st52;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st52;
-        } else
-                goto st52;
-        goto st0;
-st52:
-        if ( ++p == pe )
-                goto _test_eof52;
-case 52:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st53;
-                case 95: goto st53;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st53;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st53;
-        } else
-                goto st53;
-        goto st0;
-st53:
-        if ( ++p == pe )
-                goto _test_eof53;
-case 53:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st54;
-                case 95: goto st54;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st54;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st54;
-        } else
-                goto st54;
-        goto st0;
-st54:
-        if ( ++p == pe )
-                goto _test_eof54;
-case 54:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st55;
-                case 95: goto st55;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st55;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st55;
-        } else
-                goto st55;
-        goto st0;
-st55:
-        if ( ++p == pe )
-                goto _test_eof55;
-case 55:
-        switch( (*p) ) {
-                case 32: goto tr2;
-                case 36: goto st56;
-                case 95: goto st56;
-        }
-        if ( (*p) < 48 ) {
-                if ( 45 <= (*p) && (*p) <= 46 )
-                        goto st56;
-        } else if ( (*p) > 57 ) {
-                if ( 65 <= (*p) && (*p) <= 90 )
-                        goto st56;
-        } else
-                goto st56;
-        goto st0;
-st56:
-        if ( ++p == pe )
-                goto _test_eof56;
-case 56:
-        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_eof: {}
-        _out: {}
-        }
-#line 122 "http11_parser.rl"
-
-  if (!http_parser_has_error(parser))
-    parser->cs = cs;
-  parser->nread += p - (buffer + off);
-
-  assert(p <= pe && "buffer overflow after parsing execute");
-  assert(parser->nread <= len && "nread longer than length");
-  assert(parser->body_start <= len && "body starts after buffer end");
-  assert(parser->mark < len && "mark is after buffer end");
-  assert(parser->field_len <= len && "field has length longer than whole buffer");
-  assert(parser->field_start < len && "field starts after buffer end");
-
-  return(parser->nread);
-}
-
-int http_parser_finish(http_parser *parser)
-{
-  if (http_parser_has_error(parser) ) {
-    return -1;
-  } else if (http_parser_is_finished(parser) ) {
-    return 1;
-  } else {
-    return 0;
-  }
-}
-
-int http_parser_has_error(http_parser *parser) {
-  return parser->cs == http_parser_error;
-}
-
-int http_parser_is_finished(http_parser *parser) {
-  return parser->cs == http_parser_first_final;
-}
diff --git a/ext/unicorn/http11/http11_parser.h b/ext/unicorn/http11/http11_parser.h
index 6c332fe..8d95c59 100644
--- a/ext/unicorn/http11/http11_parser.h
+++ b/ext/unicorn/http11/http11_parser.h
@@ -1,20 +1,29 @@
+
+#line 1 "http11_parser.rl"
 /**
  * Copyright (c) 2005 Zed A. Shaw
  * You can redistribute it and/or modify it under the same terms as Ruby.
  */
-
 #ifndef http11_parser_h
 #define http11_parser_h
 
 #include <sys/types.h>
 
-typedef void (*element_cb)(void *data, const char *at, size_t length);
-typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
+static void http_field(void *data, const char *field,
+                       size_t flen, const char *value, size_t vlen);
+static void request_method(void *data, const char *at, size_t length);
+static void scheme(void *data, const char *at, size_t length);
+static void host(void *data, const char *at, size_t length);
+static void request_uri(void *data, const char *at, size_t length);
+static void fragment(void *data, const char *at, size_t length);
+static void request_path(void *data, const char *at, size_t length);
+static void query_string(void *data, const char *at, size_t length);
+static void http_version(void *data, const char *at, size_t length);
+static void header_done(void *data, const char *at, size_t length);
 
-typedef struct http_parser {
+typedef struct http_parser {
   int cs;
   size_t body_start;
-  int content_len;
   size_t nread;
   size_t mark;
   size_t field_start;
@@ -22,22 +31,1259 @@ typedef struct http_parser {
   size_t query_start;
 
   void *data;
-
-  field_cb http_field;
-  element_cb request_method;
-  element_cb request_uri;
-  element_cb fragment;
-  element_cb request_path;
-  element_cb query_string;
-  element_cb http_version;
-  element_cb header_done;
-  
 } http_parser;
 
-int http_parser_init(http_parser *parser);
-int http_parser_finish(http_parser *parser);
-size_t http_parser_execute(http_parser *parser, const char *data, size_t len);
-int http_parser_has_error(http_parser *parser);
-int http_parser_is_finished(http_parser *parser);
+static int http_parser_has_error(http_parser *parser);
+static int http_parser_is_finished(http_parser *parser);
+
+/*
+ * capitalizes all lower-case ASCII characters,
+ * converts dashes to underscores.
+ */
+static void snake_upcase_char(char *c)
+{
+  if (*c >= 'a' && *c <= 'z')
+    *c &= ~0x20;
+  else if (*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)
+
+/** Machine **/
+
+
+#line 109 "http11_parser.rl"
+
+
+/** Data **/
+
+#line 70 "http11_parser.h"
+static const int http_parser_start = 1;
+static const int http_parser_first_final = 63;
+static const int http_parser_error = 0;
+
+static const int http_parser_en_main = 1;
+
+
+#line 113 "http11_parser.rl"
+
+static void http_parser_init(http_parser *parser) {
+  int cs = 0;
+  memset(parser, 0, sizeof(*parser));
+
+#line 84 "http11_parser.h"
+        {
+        cs = http_parser_start;
+        }
+
+#line 118 "http11_parser.rl"
+  parser->cs = cs;
+}
+
+/** exec **/
+static void http_parser_execute(
+  http_parser *parser, const char *buffer, size_t len)
+{
+  const char *p, *pe;
+  int cs = parser->cs;
+  size_t off = parser->nread;
+
+  assert(off <= len && "offset past end of buffer");
+
+  p = buffer+off;
+  pe = buffer+len;
+
+  assert(*pe == '\0' && "pointer does not end on NUL");
+  assert(pe - p == len - off && "pointers aren't same distance");
+
+
+#line 110 "http11_parser.h"
+        {
+        if ( p == pe )
+                goto _test_eof;
+        switch ( cs )
+        {
+case 1:
+        switch( (*p) ) {
+                case 36: goto tr0;
+                case 95: goto tr0;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto tr0;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto tr0;
+        } else
+                goto tr0;
+        goto st0;
+st0:
+cs = 0;
+        goto _out;
+tr0:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st2;
+st2:
+        if ( ++p == pe )
+                goto _test_eof2;
+case 2:
+#line 141 "http11_parser.h"
+        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;
+        goto st0;
+tr2:
+#line 77 "http11_parser.rl"
+        {
+    request_method(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st3;
+st3:
+        if ( ++p == pe )
+                goto _test_eof3;
+case 3:
+#line 166 "http11_parser.h"
+        switch( (*p) ) {
+                case 42: goto tr4;
+                case 47: goto tr5;
+                case 72: goto tr6;
+                case 104: goto tr6;
+        }
+        goto st0;
+tr4:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st4;
+st4:
+        if ( ++p == pe )
+                goto _test_eof4;
+case 4:
+#line 182 "http11_parser.h"
+        switch( (*p) ) {
+                case 32: goto tr7;
+                case 35: goto tr8;
+        }
+        goto st0;
+tr7:
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st5;
+tr30:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+#line 85 "http11_parser.rl"
+        {
+    fragment(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st5;
+tr33:
+#line 85 "http11_parser.rl"
+        {
+    fragment(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st5;
+tr37:
+#line 98 "http11_parser.rl"
+        {
+    request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+  }
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st5;
+tr48:
+#line 89 "http11_parser.rl"
+        {MARK(query_start, p); }
+#line 90 "http11_parser.rl"
+        {
+    query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+  }
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st5;
+tr52:
+#line 90 "http11_parser.rl"
+        {
+    query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+  }
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st5;
+st5:
+        if ( ++p == pe )
+                goto _test_eof5;
+case 5:
+#line 244 "http11_parser.h"
+        if ( (*p) == 72 )
+                goto tr9;
+        goto st0;
+tr9:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st6;
+st6:
+        if ( ++p == pe )
+                goto _test_eof6;
+case 6:
+#line 256 "http11_parser.h"
+        if ( (*p) == 84 )
+                goto st7;
+        goto st0;
+st7:
+        if ( ++p == pe )
+                goto _test_eof7;
+case 7:
+        if ( (*p) == 84 )
+                goto st8;
+        goto st0;
+st8:
+        if ( ++p == pe )
+                goto _test_eof8;
+case 8:
+        if ( (*p) == 80 )
+                goto st9;
+        goto st0;
+st9:
+        if ( ++p == pe )
+                goto _test_eof9;
+case 9:
+        if ( (*p) == 47 )
+                goto st10;
+        goto st0;
+st10:
+        if ( ++p == pe )
+                goto _test_eof10;
+case 10:
+        if ( 48 <= (*p) && (*p) <= 57 )
+                goto st11;
+        goto st0;
+st11:
+        if ( ++p == pe )
+                goto _test_eof11;
+case 11:
+        if ( (*p) == 46 )
+                goto st12;
+        if ( 48 <= (*p) && (*p) <= 57 )
+                goto st11;
+        goto st0;
+st12:
+        if ( ++p == pe )
+                goto _test_eof12;
+case 12:
+        if ( 48 <= (*p) && (*p) <= 57 )
+                goto st13;
+        goto st0;
+st13:
+        if ( ++p == pe )
+                goto _test_eof13;
+case 13:
+        if ( (*p) == 13 )
+                goto tr17;
+        if ( 48 <= (*p) && (*p) <= 57 )
+                goto st13;
+        goto st0;
+tr17:
+#line 94 "http11_parser.rl"
+        {
+    http_version(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st14;
+tr25:
+#line 73 "http11_parser.rl"
+        { MARK(mark, p); }
+#line 74 "http11_parser.rl"
+        {
+    http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st14;
+tr28:
+#line 74 "http11_parser.rl"
+        {
+    http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st14;
+st14:
+        if ( ++p == pe )
+                goto _test_eof14;
+case 14:
+#line 337 "http11_parser.h"
+        if ( (*p) == 10 )
+                goto st15;
+        goto st0;
+st15:
+        if ( ++p == pe )
+                goto _test_eof15;
+case 15:
+        switch( (*p) ) {
+                case 13: goto st16;
+                case 33: goto tr20;
+                case 124: goto tr20;
+                case 126: goto tr20;
+        }
+        if ( (*p) < 45 ) {
+                if ( (*p) > 39 ) {
+                        if ( 42 <= (*p) && (*p) <= 43 )
+                                goto tr20;
+                } else if ( (*p) >= 35 )
+                        goto tr20;
+        } else if ( (*p) > 46 ) {
+                if ( (*p) < 65 ) {
+                        if ( 48 <= (*p) && (*p) <= 57 )
+                                goto tr20;
+                } else if ( (*p) > 90 ) {
+                        if ( 94 <= (*p) && (*p) <= 122 )
+                                goto tr20;
+                } else
+                        goto tr20;
+        } else
+                goto tr20;
+        goto st0;
+st16:
+        if ( ++p == pe )
+                goto _test_eof16;
+case 16:
+        if ( (*p) == 10 )
+                goto tr21;
+        goto st0;
+tr21:
+#line 102 "http11_parser.rl"
+        {
+    parser->body_start = p - buffer + 1;
+    header_done(parser->data, p + 1, pe - p - 1);
+    {p++; cs = 63; goto _out;}
+  }
+        goto st63;
+st63:
+        if ( ++p == pe )
+                goto _test_eof63;
+case 63:
+#line 388 "http11_parser.h"
+        goto st0;
+tr20:
+#line 66 "http11_parser.rl"
+        { MARK(field_start, p); }
+#line 67 "http11_parser.rl"
+        { snake_upcase_char((char *)p); }
+        goto st17;
+tr22:
+#line 67 "http11_parser.rl"
+        { snake_upcase_char((char *)p); }
+        goto st17;
+st17:
+        if ( ++p == pe )
+                goto _test_eof17;
+case 17:
+#line 404 "http11_parser.h"
+        switch( (*p) ) {
+                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 tr22;
+                } else if ( (*p) >= 35 )
+                        goto tr22;
+        } else if ( (*p) > 46 ) {
+                if ( (*p) < 65 ) {
+                        if ( 48 <= (*p) && (*p) <= 57 )
+                                goto tr22;
+                } else if ( (*p) > 90 ) {
+                        if ( 94 <= (*p) && (*p) <= 122 )
+                                goto tr22;
+                } else
+                        goto tr22;
+        } else
+                goto tr22;
+        goto st0;
+tr23:
+#line 69 "http11_parser.rl"
+        {
+    parser->field_len = LEN(field_start, p);
+  }
+        goto st18;
+tr26:
+#line 73 "http11_parser.rl"
+        { MARK(mark, p); }
+        goto st18;
+st18:
+        if ( ++p == pe )
+                goto _test_eof18;
+case 18:
+#line 443 "http11_parser.h"
+        switch( (*p) ) {
+                case 13: goto tr25;
+                case 32: goto tr26;
+        }
+        goto tr24;
+tr24:
+#line 73 "http11_parser.rl"
+        { MARK(mark, p); }
+        goto st19;
+st19:
+        if ( ++p == pe )
+                goto _test_eof19;
+case 19:
+#line 457 "http11_parser.h"
+        if ( (*p) == 13 )
+                goto tr28;
+        goto st19;
+tr8:
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st20;
+tr38:
+#line 98 "http11_parser.rl"
+        {
+    request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+  }
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st20;
+tr49:
+#line 89 "http11_parser.rl"
+        {MARK(query_start, p); }
+#line 90 "http11_parser.rl"
+        {
+    query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+  }
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st20;
+tr53:
+#line 90 "http11_parser.rl"
+        {
+    query_string(parser->data, PTR_TO(query_start), LEN(query_start, p));
+  }
+#line 82 "http11_parser.rl"
+        {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, p));
+  }
+        goto st20;
+st20:
+        if ( ++p == pe )
+                goto _test_eof20;
+case 20:
+#line 503 "http11_parser.h"
+        switch( (*p) ) {
+                case 32: goto tr30;
+                case 35: goto st0;
+                case 37: goto tr31;
+                case 127: goto st0;
+        }
+        if ( 0 <= (*p) && (*p) <= 31 )
+                goto st0;
+        goto tr29;
+tr29:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st21;
+st21:
+        if ( ++p == pe )
+                goto _test_eof21;
+case 21:
+#line 521 "http11_parser.h"
+        switch( (*p) ) {
+                case 32: goto tr33;
+                case 35: goto st0;
+                case 37: goto st22;
+                case 127: goto st0;
+        }
+        if ( 0 <= (*p) && (*p) <= 31 )
+                goto st0;
+        goto st21;
+tr31:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st22;
+st22:
+        if ( ++p == pe )
+                goto _test_eof22;
+case 22:
+#line 539 "http11_parser.h"
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st23;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st23;
+        } else
+                goto st23;
+        goto st0;
+st23:
+        if ( ++p == pe )
+                goto _test_eof23;
+case 23:
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st21;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st21;
+        } else
+                goto st21;
+        goto st0;
+tr5:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st24;
+tr65:
+#line 81 "http11_parser.rl"
+        { host(parser->data, PTR_TO(mark), LEN(mark, p)); }
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st24;
+st24:
+        if ( ++p == pe )
+                goto _test_eof24;
+case 24:
+#line 576 "http11_parser.h"
+        switch( (*p) ) {
+                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 st24;
+st25:
+        if ( ++p == pe )
+                goto _test_eof25;
+case 25:
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st26;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st26;
+        } else
+                goto st26;
+        goto st0;
+st26:
+        if ( ++p == pe )
+                goto _test_eof26;
+case 26:
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st24;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st24;
+        } else
+                goto st24;
+        goto st0;
+tr40:
+#line 98 "http11_parser.rl"
+        {
+    request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+  }
+        goto st27;
+st27:
+        if ( ++p == pe )
+                goto _test_eof27;
+case 27:
+#line 624 "http11_parser.h"
+        switch( (*p) ) {
+                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 st27;
+st28:
+        if ( ++p == pe )
+                goto _test_eof28;
+case 28:
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st29;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st29;
+        } else
+                goto st29;
+        goto st0;
+st29:
+        if ( ++p == pe )
+                goto _test_eof29;
+case 29:
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st27;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st27;
+        } else
+                goto st27;
+        goto st0;
+tr41:
+#line 98 "http11_parser.rl"
+        {
+    request_path(parser->data, PTR_TO(mark), LEN(mark,p));
+  }
+        goto st30;
+st30:
+        if ( ++p == pe )
+                goto _test_eof30;
+case 30:
+#line 671 "http11_parser.h"
+        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 89 "http11_parser.rl"
+        {MARK(query_start, p); }
+        goto st31;
+st31:
+        if ( ++p == pe )
+                goto _test_eof31;
+case 31:
+#line 689 "http11_parser.h"
+        switch( (*p) ) {
+                case 32: goto tr52;
+                case 35: goto tr53;
+                case 37: goto st32;
+                case 127: goto st0;
+        }
+        if ( 0 <= (*p) && (*p) <= 31 )
+                goto st0;
+        goto st31;
+tr50:
+#line 89 "http11_parser.rl"
+        {MARK(query_start, p); }
+        goto st32;
+st32:
+        if ( ++p == pe )
+                goto _test_eof32;
+case 32:
+#line 707 "http11_parser.h"
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st33;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st33;
+        } else
+                goto st33;
+        goto st0;
+st33:
+        if ( ++p == pe )
+                goto _test_eof33;
+case 33:
+        if ( (*p) < 65 ) {
+                if ( 48 <= (*p) && (*p) <= 57 )
+                        goto st31;
+        } else if ( (*p) > 70 ) {
+                if ( 97 <= (*p) && (*p) <= 102 )
+                        goto st31;
+        } else
+                goto st31;
+        goto st0;
+tr6:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+#line 68 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st34;
+st34:
+        if ( ++p == pe )
+                goto _test_eof34;
+case 34:
+#line 740 "http11_parser.h"
+        switch( (*p) ) {
+                case 84: goto tr56;
+                case 116: goto tr56;
+        }
+        goto st0;
+tr56:
+#line 68 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st35;
+st35:
+        if ( ++p == pe )
+                goto _test_eof35;
+case 35:
+#line 754 "http11_parser.h"
+        switch( (*p) ) {
+                case 84: goto tr57;
+                case 116: goto tr57;
+        }
+        goto st0;
+tr57:
+#line 68 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st36;
+st36:
+        if ( ++p == pe )
+                goto _test_eof36;
+case 36:
+#line 768 "http11_parser.h"
+        switch( (*p) ) {
+                case 80: goto tr58;
+                case 112: goto tr58;
+        }
+        goto st0;
+tr58:
+#line 68 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st37;
+st37:
+        if ( ++p == pe )
+                goto _test_eof37;
+case 37:
+#line 782 "http11_parser.h"
+        switch( (*p) ) {
+                case 58: goto tr59;
+                case 83: goto tr60;
+                case 115: goto tr60;
+        }
+        goto st0;
+tr59:
+#line 80 "http11_parser.rl"
+        { scheme(parser->data, PTR_TO(mark), LEN(mark, p)); }
+        goto st38;
+st38:
+        if ( ++p == pe )
+                goto _test_eof38;
+case 38:
+#line 797 "http11_parser.h"
+        if ( (*p) == 47 )
+                goto st39;
+        goto st0;
+st39:
+        if ( ++p == pe )
+                goto _test_eof39;
+case 39:
+        if ( (*p) == 47 )
+                goto st40;
+        goto st0;
+st40:
+        if ( ++p == pe )
+                goto _test_eof40;
+case 40:
+        if ( (*p) == 95 )
+                goto tr63;
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto tr63;
+        } else if ( (*p) > 57 ) {
+                if ( (*p) > 90 ) {
+                        if ( 97 <= (*p) && (*p) <= 122 )
+                                goto tr63;
+                } else if ( (*p) >= 65 )
+                        goto tr63;
+        } else
+                goto tr63;
+        goto st0;
+tr63:
+#line 64 "http11_parser.rl"
+        {MARK(mark, p); }
+        goto st41;
+st41:
+        if ( ++p == pe )
+                goto _test_eof41;
+case 41:
+#line 834 "http11_parser.h"
+        switch( (*p) ) {
+                case 47: goto tr65;
+                case 58: goto st42;
+                case 95: goto st41;
+        }
+        if ( (*p) < 65 ) {
+                if ( 45 <= (*p) && (*p) <= 57 )
+                        goto st41;
+        } else if ( (*p) > 90 ) {
+                if ( 97 <= (*p) && (*p) <= 122 )
+                        goto st41;
+        } else
+                goto st41;
+        goto st0;
+st42:
+        if ( ++p == pe )
+                goto _test_eof42;
+case 42:
+        if ( (*p) == 47 )
+                goto tr65;
+        if ( 48 <= (*p) && (*p) <= 57 )
+                goto st42;
+        goto st0;
+tr60:
+#line 68 "http11_parser.rl"
+        { downcase_char((char *)p); }
+        goto st43;
+st43:
+        if ( ++p == pe )
+                goto _test_eof43;
+case 43:
+#line 866 "http11_parser.h"
+        if ( (*p) == 58 )
+                goto tr59;
+        goto st0;
+st44:
+        if ( ++p == pe )
+                goto _test_eof44;
+case 44:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st45;
+                case 95: goto st45;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st45;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st45;
+        } else
+                goto st45;
+        goto st0;
+st45:
+        if ( ++p == pe )
+                goto _test_eof45;
+case 45:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st46;
+                case 95: goto st46;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st46;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st46;
+        } else
+                goto st46;
+        goto st0;
+st46:
+        if ( ++p == pe )
+                goto _test_eof46;
+case 46:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st47;
+                case 95: goto st47;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st47;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st47;
+        } else
+                goto st47;
+        goto st0;
+st47:
+        if ( ++p == pe )
+                goto _test_eof47;
+case 47:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st48;
+                case 95: goto st48;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st48;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st48;
+        } else
+                goto st48;
+        goto st0;
+st48:
+        if ( ++p == pe )
+                goto _test_eof48;
+case 48:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st49;
+                case 95: goto st49;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st49;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st49;
+        } else
+                goto st49;
+        goto st0;
+st49:
+        if ( ++p == pe )
+                goto _test_eof49;
+case 49:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st50;
+                case 95: goto st50;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st50;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st50;
+        } else
+                goto st50;
+        goto st0;
+st50:
+        if ( ++p == pe )
+                goto _test_eof50;
+case 50:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st51;
+                case 95: goto st51;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st51;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st51;
+        } else
+                goto st51;
+        goto st0;
+st51:
+        if ( ++p == pe )
+                goto _test_eof51;
+case 51:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st52;
+                case 95: goto st52;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st52;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st52;
+        } else
+                goto st52;
+        goto st0;
+st52:
+        if ( ++p == pe )
+                goto _test_eof52;
+case 52:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st53;
+                case 95: goto st53;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st53;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st53;
+        } else
+                goto st53;
+        goto st0;
+st53:
+        if ( ++p == pe )
+                goto _test_eof53;
+case 53:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st54;
+                case 95: goto st54;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st54;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st54;
+        } else
+                goto st54;
+        goto st0;
+st54:
+        if ( ++p == pe )
+                goto _test_eof54;
+case 54:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st55;
+                case 95: goto st55;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st55;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st55;
+        } else
+                goto st55;
+        goto st0;
+st55:
+        if ( ++p == pe )
+                goto _test_eof55;
+case 55:
+        switch( (*p) ) {
+                case 32: goto tr2;
+                case 36: goto st56;
+                case 95: goto st56;
+        }
+        if ( (*p) < 48 ) {
+                if ( 45 <= (*p) && (*p) <= 46 )
+                        goto st56;
+        } else if ( (*p) > 57 ) {
+                if ( 65 <= (*p) && (*p) <= 90 )
+                        goto st56;
+        } else
+                goto st56;
+        goto st0;
+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_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 138 "http11_parser.rl"
+
+  if (!http_parser_has_error(parser))
+    parser->cs = cs;
+  parser->nread += p - (buffer + off);
+
+  assert(p <= pe && "buffer overflow after parsing execute");
+  assert(parser->nread <= len && "nread longer than length");
+  assert(parser->body_start <= len && "body starts after buffer end");
+  assert(parser->mark < len && "mark is after buffer end");
+  assert(parser->field_len <= len && "field has length longer than whole buffer");
+  assert(parser->field_start < len && "field starts after buffer end");
+}
+
+static int http_parser_has_error(http_parser *parser) {
+  return parser->cs == http_parser_error;
+}
 
-#endif
+static int http_parser_is_finished(http_parser *parser) {
+  return parser->cs == http_parser_first_final;
+}
+#endif /* http11_parser_h */
diff --git a/ext/unicorn/http11/http11_parser.rl b/ext/unicorn/http11/http11_parser.rl
index 1fad2ca..9894276 100644
--- a/ext/unicorn/http11/http11_parser.rl
+++ b/ext/unicorn/http11/http11_parser.rl
@@ -2,12 +2,37 @@
  * Copyright (c) 2005 Zed A. Shaw
  * You can redistribute it and/or modify it under the same terms as Ruby.
  */
-#include "http11_parser.h"
-#include <stdio.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
+#ifndef http11_parser_h
+#define http11_parser_h
+
+#include <sys/types.h>
+
+static void http_field(void *data, const char *field,
+                       size_t flen, const char *value, size_t vlen);
+static void request_method(void *data, const char *at, size_t length);
+static void scheme(void *data, const char *at, size_t length);
+static void host(void *data, const char *at, size_t length);
+static void request_uri(void *data, const char *at, size_t length);
+static void fragment(void *data, const char *at, size_t length);
+static void request_path(void *data, const char *at, size_t length);
+static void query_string(void *data, const char *at, size_t length);
+static void http_version(void *data, const char *at, size_t length);
+static void header_done(void *data, const char *at, size_t length);
+
+typedef struct http_parser {
+  int cs;
+  size_t body_start;
+  size_t nread;
+  size_t mark;
+  size_t field_start;
+  size_t field_len;
+  size_t query_start;
+
+  void *data;
+} http_parser;
+
+static int http_parser_has_error(http_parser *parser);
+static int http_parser_is_finished(http_parser *parser);
 
 /*
  * capitalizes all lower-case ASCII characters,
@@ -15,10 +40,16 @@
  */
 static void snake_upcase_char(char *c)
 {
-    if (*c >= 'a' && *c <= 'z')
-      *c &= ~0x20;
-    else if (*c == '-')
-      *c = '_';
+  if (*c >= 'a' && *c <= 'z')
+    *c &= ~0x20;
+  else if (*c == '-')
+    *c = '_';
+}
+
+static void downcase_char(char *c)
+{
+  if (*c >= 'A' && *c <= 'Z')
+    *c |= 0x20;
 }
 
 #define LEN(AT, FPC) (FPC - buffer - parser->AT)
@@ -28,84 +59,69 @@ static void snake_upcase_char(char *c)
 /** Machine **/
 
 %%{
-  
   machine http_parser;
 
   action mark {MARK(mark, fpc); }
 
-
   action start_field { MARK(field_start, fpc); }
   action snake_upcase_field { snake_upcase_char((char *)fpc); }
-  action write_field {
+  action downcase_char { downcase_char((char *)fpc); }
+  action write_field {
     parser->field_len = LEN(field_start, fpc);
   }
 
   action start_value { MARK(mark, fpc); }
-  action write_value {
-    if(parser->http_field != NULL) {
-      parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
-    }
+  action write_value {
+    http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
   }
-  action request_method {
-    if(parser->request_method != NULL)
-      parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  action request_method {
+    request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
   }
-  action request_uri {
-    if(parser->request_uri != NULL)
-      parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  action scheme { scheme(parser->data, PTR_TO(mark), LEN(mark, fpc)); }
+  action host { host(parser->data, PTR_TO(mark), LEN(mark, fpc)); }
+  action request_uri {
+    request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
   }
-  action fragment {
-    if(parser->fragment != NULL)
-      parser->fragment(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  action fragment {
+    fragment(parser->data, PTR_TO(mark), LEN(mark, fpc));
   }
 
   action start_query {MARK(query_start, fpc); }
-  action query_string {
-    if(parser->query_string != NULL)
-      parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
+  action query_string {
+    query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
   }
 
-  action http_version {        
-    if(parser->http_version != NULL)
-      parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
+  action http_version {
+    http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
   }
 
   action request_path {
-    if(parser->request_path != NULL)
-      parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
+    request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
   }
 
-  action done {
-    parser->body_start = fpc - buffer + 1;
-    if(parser->header_done != NULL)
-      parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
+  action done {
+    parser->body_start = fpc - buffer + 1;
+    header_done(parser->data, fpc + 1, pe - fpc - 1);
     fbreak;
   }
 
   include http_parser_common "http11_parser_common.rl";
-
 }%%
 
 /** Data **/
 %% write data;
 
-int http_parser_init(http_parser *parser)  {
+static void http_parser_init(http_parser *parser) {
   int cs = 0;
+  memset(parser, 0, sizeof(*parser));
   %% write init;
   parser->cs = cs;
-  parser->body_start = 0;
-  parser->content_len = 0;
-  parser->mark = 0;
-  parser->nread = 0;
-  parser->field_len = 0;
-  parser->field_start = 0;    
-
-  return(1);
 }
 
-
 /** exec **/
-size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len)  {
+static void http_parser_execute(
+  http_parser *parser, const char *buffer, size_t len)
+{
   const char *p, *pe;
   int cs = parser->cs;
   size_t off = parser->nread;
@@ -130,25 +146,13 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len)
   assert(parser->mark < len && "mark is after buffer end");
   assert(parser->field_len <= len && "field has length longer than whole buffer");
   assert(parser->field_start < len && "field starts after buffer end");
-
-  return(parser->nread);
-}
-
-int http_parser_finish(http_parser *parser)
-{
-  if (http_parser_has_error(parser) ) {
-    return -1;
-  } else if (http_parser_is_finished(parser) ) {
-    return 1;
-  } else {
-    return 0;
-  }
 }
 
-int http_parser_has_error(http_parser *parser) {
+static int http_parser_has_error(http_parser *parser) {
   return parser->cs == http_parser_error;
 }
 
-int http_parser_is_finished(http_parser *parser) {
+static int http_parser_is_finished(http_parser *parser) {
   return parser->cs == http_parser_first_final;
 }
+#endif /* http11_parser_h */
diff --git a/ext/unicorn/http11/http11_parser_common.rl b/ext/unicorn/http11/http11_parser_common.rl
index ee970b1..ae01a55 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 >mark %scheme;
+  hostname = (alnum | "-" | "." | "_")+;
+  host_with_port = (hostname (":" digit*)?) >mark %host;
 
   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.rb b/lib/unicorn.rb
index 208e6da..1f1dd45 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -1,7 +1,6 @@
-require 'logger'
 require 'fcntl'
 
-require 'unicorn/socket'
+require 'unicorn/socket_helper'
 require 'unicorn/const'
 require 'unicorn/http_request'
 require 'unicorn/http_response'
@@ -27,13 +26,13 @@ module Unicorn
     include ::Unicorn::SocketHelper
 
     SIG_QUEUE = []
-    DEFAULT_START_CTX = {
+    START_CTX = {
       :argv => ARGV.map { |arg| arg.dup },
       # don't rely on Dir.pwd here since it's not symlink-aware, and
       # symlink dirs are the default with Capistrano...
       :cwd => `/bin/sh -c pwd`.chomp("\n"),
       :zero => $0.dup,
-    }.freeze
+    }
 
     Worker = Struct.new(:nr, :tempfile) unless defined?(Worker)
     class Worker
@@ -48,9 +47,6 @@ module Unicorn
     # HttpServer.workers.join to join the thread that's processing
     # incoming requests on the socket.
     def initialize(app, options = {})
-      start_ctx = options.delete(:start_ctx)
-      @start_ctx = DEFAULT_START_CTX.dup
-      @start_ctx.merge!(start_ctx) if start_ctx
       @app = app
       @workers = Hash.new
       @io_purgatory = [] # prevents IO objects in here from being GC-ed
@@ -307,7 +303,7 @@ module Unicorn
       end
     end
 
-    # reexecutes the @start_ctx with a new binary
+    # reexecutes the START_CTX with a new binary
     def reexec
       if @reexec_pid > 0
         begin
@@ -337,8 +333,8 @@ module Unicorn
       @reexec_pid = fork do
         listener_fds = @listeners.map { |sock| sock.fileno }
         ENV['UNICORN_FD'] = listener_fds.join(',')
-        Dir.chdir(@start_ctx[:cwd])
-        cmd = [ @start_ctx[:zero] ] + @start_ctx[:argv]
+        Dir.chdir(START_CTX[:cwd])
+        cmd = [ START_CTX[:zero] ] + START_CTX[:argv]
 
         # avoid leaking FDs we don't know about, but let before_exec
         # unset FD_CLOEXEC, if anything else in the app eventually
@@ -379,9 +375,9 @@ module Unicorn
       (0...@worker_processes).each do |worker_nr|
         @workers.values.include?(worker_nr) and next
         begin
-          Dir.chdir(@start_ctx[:cwd])
+          Dir.chdir(START_CTX[:cwd])
         rescue Errno::ENOENT => err
-          logger.fatal "#{err.inspect} (#{@start_ctx[:cwd]})"
+          logger.fatal "#{err.inspect} (#{START_CTX[:cwd]})"
           SIG_QUEUE << :QUIT # forcibly emulate SIGQUIT
           return
         end
@@ -431,10 +427,11 @@ module Unicorn
       trap(:CHLD, 'DEFAULT')
       SIG_QUEUE.clear
       proc_name "worker[#{worker.nr}]"
+      START_CTX.clear
       @rd_sig.close if @rd_sig
       @wr_sig.close if @wr_sig
       @workers.values.each { |other| other.tempfile.close rescue nil }
-      @start_ctx = @workers = @rd_sig = @wr_sig = nil
+      @workers = @rd_sig = @wr_sig = nil
       @listeners.each { |sock| sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) }
       worker.tempfile.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
       @after_fork.call(self, worker) # can drop perms
@@ -588,8 +585,8 @@ module Unicorn
     end
 
     def proc_name(tag)
-      $0 = ([ File.basename(@start_ctx[:zero]), tag ] +
-              @start_ctx[:argv]).join(' ')
+      $0 = ([ File.basename(START_CTX[:zero]), tag ] +
+              START_CTX[:argv]).join(' ')
     end
 
   end
diff --git a/lib/unicorn/configurator.rb b/lib/unicorn/configurator.rb
index b27121e..bd06996 100644
--- a/lib/unicorn/configurator.rb
+++ b/lib/unicorn/configurator.rb
@@ -1,5 +1,4 @@
-require 'unicorn/socket'
-require 'unicorn/const'
+require 'socket'
 require 'logger'
 
 module Unicorn
diff --git a/lib/unicorn/const.rb b/lib/unicorn/const.rb
index 80731ab..c05d333 100644
--- a/lib/unicorn/const.rb
+++ b/lib/unicorn/const.rb
@@ -58,8 +58,6 @@ module Unicorn
 
     UNICORN_VERSION="0.5.3".freeze
 
-    UNICORN_TMP_BASE="unicorn".freeze
-
     DEFAULT_HOST = "0.0.0.0".freeze # default TCP listen host address
     DEFAULT_PORT = "8080".freeze    # default TCP listen port
     DEFAULT_LISTEN = "#{DEFAULT_HOST}:#{DEFAULT_PORT}".freeze
@@ -82,7 +80,6 @@ module Unicorn
     CONTENT_LENGTH="CONTENT_LENGTH".freeze
     REMOTE_ADDR="REMOTE_ADDR".freeze
     HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze
-    QUERY_STRING="QUERY_STRING".freeze
     RACK_INPUT="rack.input".freeze
   end
 
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index 399aee5..24da085 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
@@ -19,11 +18,11 @@ module Unicorn
        "rack.multiprocess" => true,
        "rack.multithread" => false,
        "rack.run_once" => false,
-       "rack.version" => [0, 1],
-       "SCRIPT_NAME" => "",
+       "rack.version" => [0, 1].freeze,
+       "SCRIPT_NAME" => "".freeze,
 
        # this is not in the Rack spec, but some apps may rely on it
-       "SERVER_SOFTWARE" => "Unicorn #{Const::UNICORN_VERSION}"
+       "SERVER_SOFTWARE" => "Unicorn #{Const::UNICORN_VERSION}".freeze
      }.freeze
 
     def initialize(logger)
@@ -56,6 +55,16 @@ module Unicorn
     # This does minimal exception trapping and it is up to the caller
     # to handle any socket errors (e.g. user aborted upload).
     def read(socket)
+      # From http://www.ietf.org/rfc/rfc3875:
+      # "Script authors should be aware that the REMOTE_ADDR and
+      #  REMOTE_HOST meta-variables (see sections 4.1.8 and 4.1.9)
+      #  may not identify the ultimate source of the request.  They
+      #  identify the client for the immediate request to the server;
+      #  that client may be a proxy, gateway, or other intermediary
+      #  acting on behalf of the actual source client."
+      @params[Const::REMOTE_ADDR] =
+                    TCPSocket === socket ? socket.peeraddr.last : '127.0.0.1'
+
       # short circuit the common case with small GET requests first
       @parser.execute(@params, read_socket(socket)) and
           return handle_body(socket)
@@ -71,7 +80,7 @@ module Unicorn
       rescue HttpParserError => e
         @logger.error "HTTP parse error, malformed request " \
                       "(#{@params[Const::HTTP_X_FORWARDED_FOR] ||
-                          socket.unicorn_peeraddr}): #{e.inspect}"
+                          @params[Const::REMOTE_ADDR]}): #{e.inspect}"
         @logger.error "REQUEST DATA: #{data.inspect}\n---\n" \
                       "PARAMS: #{@params.inspect}\n---\n"
         raise e
@@ -87,7 +96,7 @@ module Unicorn
       remain = content_length - http_body.length
 
       # must read more data to complete body
-      @body = remain < Const::MAX_BODY ? StringIO.new : Tempfile.new('')
+      @body = remain < Const::MAX_BODY ? StringIO.new : Tempfile.new('unicorn')
       @body.binmode
       @body.sync = true
       @body.syswrite(http_body)
@@ -116,22 +125,6 @@ module Unicorn
       # over the HTTP response.
       # @params["unicorn.client"] = socket
 
-      # From http://www.ietf.org/rfc/rfc3875:
-      # "Script authors should be aware that the REMOTE_ADDR and
-      #  REMOTE_HOST meta-variables (see sections 4.1.8 and 4.1.9)
-      #  may not identify the ultimate source of the request.  They
-      #  identify the client for the immediate request to the server;
-      #  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)
     end
diff --git a/lib/unicorn/http_response.rb b/lib/unicorn/http_response.rb
index b355ad4..6b6fa07 100644
--- a/lib/unicorn/http_response.rb
+++ b/lib/unicorn/http_response.rb
@@ -64,15 +64,12 @@ module Unicorn
       # write(2) can return short on slow devices like sockets as well
       # as fail with EINTR if a signal was caught.
       def self.socket_write(socket, buffer)
-        loop do
-          begin
-            written = socket.syswrite(buffer)
-            return written if written == buffer.length
-            buffer = buffer[written..-1]
-          rescue Errno::EINTR
-            retry
-          end
-        end
+        begin
+          written = socket.syswrite(buffer)
+          return written if written == buffer.length
+          buffer = buffer[written..-1]
+        rescue Errno::EINTR
+        end while true
       end
 
   end
diff --git a/lib/unicorn/socket.rb b/lib/unicorn/socket_helper.rb
index 5a3bfd7..850ad85 100644
--- a/lib/unicorn/socket.rb
+++ b/lib/unicorn/socket_helper.rb
@@ -1,18 +1,5 @@
 require 'socket'
 
-class UNIXSocket
-  UNICORN_PEERADDR = '127.0.0.1'.freeze
-  def unicorn_peeraddr
-    UNICORN_PEERADDR
-  end
-end
-
-class TCPSocket
-  def unicorn_peeraddr
-    peeraddr.last
-  end
-end
-
 module Unicorn
   module SocketHelper
     include Socket::Constants
diff --git a/test/exec/test_exec.rb b/test/exec/test_exec.rb
index 888f7c7..b0462dc 100644
--- a/test/exec/test_exec.rb
+++ b/test/exec/test_exec.rb
@@ -459,6 +459,7 @@ end
     results = nil
     sock = Tempfile.new('unicorn_test_sock')
     sock_path = sock.path
+    @sockets << sock_path
     sock.close!
     ucfg = Tempfile.new('unicorn_test_config')
     ucfg.syswrite("listen \"#{sock_path}\"\n")
diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb
index f6fdd47..a158ebb 100644
--- a/test/unit/test_http_parser.rb
+++ b/test/unit/test_http_parser.rb
@@ -22,7 +22,7 @@ class HttpParserTest < Test::Unit::TestCase
     assert_equal '/', req['REQUEST_URI']
     assert_equal 'GET', req['REQUEST_METHOD']
     assert_nil req['FRAGMENT']
-    assert_nil req['QUERY_STRING']
+    assert_equal '', req['QUERY_STRING']
 
     parser.reset
     req.clear
@@ -40,7 +40,40 @@ class HttpParserTest < Test::Unit::TestCase
     assert_equal '/hello-world', req['REQUEST_URI']
     assert_equal 'GET', req['REQUEST_METHOD']
     assert_nil req['FRAGMENT']
-    assert_nil req['QUERY_STRING']
+    assert_equal '', req['QUERY_STRING']
+  end
+
+  def test_parse_server_host_default_port
+    parser = HttpParser.new
+    req = {}
+    assert parser.execute(req, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n")
+    assert_equal 'foo', req['SERVER_NAME']
+    assert_equal '80', req['SERVER_PORT']
+  end
+
+  def test_parse_server_host_alt_port
+    parser = HttpParser.new
+    req = {}
+    assert parser.execute(req, "GET / HTTP/1.1\r\nHost: foo:999\r\n\r\n")
+    assert_equal 'foo', req['SERVER_NAME']
+    assert_equal '999', req['SERVER_PORT']
+  end
+
+  def test_parse_server_host_empty_port
+    parser = HttpParser.new
+    req = {}
+    assert parser.execute(req, "GET / HTTP/1.1\r\nHost: foo:\r\n\r\n")
+    assert_equal 'foo', req['SERVER_NAME']
+    assert_equal '80', req['SERVER_PORT']
+  end
+
+  def test_parse_server_host_xfp_https
+    parser = HttpParser.new
+    req = {}
+    assert parser.execute(req, "GET / HTTP/1.1\r\nHost: foo:\r\n" \
+                          "X-Forwarded-Proto: https\r\n\r\n")
+    assert_equal 'foo', req['SERVER_NAME']
+    assert_equal '443', req['SERVER_PORT']
   end
 
   def test_parse_strange_headers
@@ -100,7 +133,88 @@ class HttpParserTest < Test::Unit::TestCase
     assert parser.execute(req, http << "\n")
     assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL']
     assert_nil req['FRAGMENT']
-    assert_nil req['QUERY_STRING']
+    assert_equal '', req['QUERY_STRING']
+  end
+
+  # not common, but underscores do appear in practice
+  def test_absolute_uri_underscores
+    parser = HttpParser.new
+    req = {}
+    http = "GET http://under_score.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 'under_score.example.com', req['HTTP_HOST']
+    assert_equal 'under_score.example.com', req['SERVER_NAME']
+    assert_equal '80', req['SERVER_PORT']
+  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']
+    assert_equal 'example.com', req['SERVER_NAME']
+    assert_equal '80', req['SERVER_PORT']
+  end
+
+  # X-Forwarded-Proto is not in rfc2616, absolute URIs are, however...
+  def test_absolute_uri_https
+    parser = HttpParser.new
+    req = {}
+    http = "GET https://example.com/foo?q=bar HTTP/1.1\r\n" \
+           "X-Forwarded-Proto: http\r\n\r\n"
+    assert parser.execute(req, http)
+    assert_equal 'https', 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']
+    assert_equal 'example.com', req['SERVER_NAME']
+    assert_equal '443', req['SERVER_PORT']
+  end
+
+  # Host: header should be ignored for absolute URIs
+  def test_absolute_uri_with_port
+    parser = HttpParser.new
+    req = {}
+    http = "GET http://example.com:8080/foo?q=bar HTTP/1.2\r\n" \
+           "Host: bad.example.com\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:8080', req['HTTP_HOST']
+    assert_equal 'example.com', req['SERVER_NAME']
+    assert_equal '8080', req['SERVER_PORT']
+  end
+
+  def test_absolute_uri_with_empty_port
+    parser = HttpParser.new
+    req = {}
+    http = "GET https://example.com:/foo?q=bar HTTP/1.1\r\n" \
+           "Host: bad.example.com\r\n\r\n"
+    assert parser.execute(req, http)
+    assert_equal 'https', 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']
+    assert_equal 'example.com', req['SERVER_NAME']
+    assert_equal '443', req['SERVER_PORT']
   end
 
   def test_put_body_oneshot
diff --git a/test/unit/test_request.rb b/test/unit/test_request.rb
index 0613326..7c438da 100644
--- a/test/unit/test_request.rb
+++ b/test/unit/test_request.rb
@@ -19,11 +19,7 @@ include Unicorn
 
 class RequestTest < Test::Unit::TestCase
 
-  class MockRequest < StringIO
-    def unicorn_peeraddr
-      '666.666.666.666'
-    end
-  end
+  class MockRequest < StringIO; end
 
   def setup
     @request = HttpRequest.new(Logger.new($stderr))
@@ -38,23 +34,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" \
@@ -90,7 +119,7 @@ class RequestTest < Test::Unit::TestCase
     res = env = nil
     assert_nothing_raised { env = @request.read(client) }
     assert_equal "http", env['rack.url_scheme']
-    assert_equal '666.666.666.666', env['REMOTE_ADDR']
+    assert_equal '127.0.0.1', env['REMOTE_ADDR']
     assert_nothing_raised { res = @lint.call(env) }
   end
 
@@ -113,9 +142,6 @@ class RequestTest < Test::Unit::TestCase
     buf = (' ' * bs).freeze
     length = bs * count
     client = Tempfile.new('big_put')
-    def client.unicorn_peeraddr
-      '1.1.1.1'
-    end
     client.syswrite(
       "PUT / HTTP/1.1\r\n" \
       "Host: foo\r\n" \
diff --git a/test/unit/test_socket_helper.rb b/test/unit/test_socket_helper.rb
index 0608e24..3e28cb9 100644
--- a/test/unit/test_socket_helper.rb
+++ b/test/unit/test_socket_helper.rb
@@ -123,49 +123,4 @@ class TestSocketHelper < Test::Unit::TestCase
     sock_name(@unix_server)
   end
 
-  def test_tcp_unicorn_peeraddr
-    test_bind_listen_tcp
-    @tcp_server = server_cast(@tcp_listener)
-    tmp = Tempfile.new 'shared'
-    pid = fork do
-      client = @tcp_server.accept
-      IO.select([client])
-      assert_equal GET_SLASH, client.sysread(GET_SLASH.size)
-      tmp.syswrite "#{client.unicorn_peeraddr}"
-      exit 0
-    end
-    host, port = sock_name(@tcp_server).split(/:/)
-    client = TCPSocket.new(host, port.to_i)
-    client.syswrite(GET_SLASH)
-
-    pid, status = Process.waitpid2(pid)
-    assert_nothing_raised { client.close }
-    assert status.success?
-    tmp.sysseek 0
-    assert_equal @test_addr, tmp.sysread(4096)
-    tmp.sysseek 0
-  end
-
-  def test_unix_unicorn_peeraddr
-    test_bind_listen_unix
-    @unix_server = server_cast(@unix_listener)
-    tmp = Tempfile.new 'shared'
-    pid = fork do
-      client = @unix_server.accept
-      IO.select([client])
-      assert_equal GET_SLASH, client.sysread(4096)
-      tmp.syswrite "#{client.unicorn_peeraddr}"
-      exit 0
-    end
-    client = UNIXSocket.new(@unix_listener_path)
-    client.syswrite(GET_SLASH)
-
-    pid, status = Process.waitpid2(pid)
-    assert_nothing_raised { client.close }
-    assert status.success?
-    tmp.sysseek 0
-    assert_equal '127.0.0.1', tmp.sysread(4096)
-    tmp.sysseek 0
-  end
-
 end
diff --git a/test/unit/test_upload.rb b/test/unit/test_upload.rb
index 86b6c6c..b06dfdb 100644
--- a/test/unit/test_upload.rb
+++ b/test/unit/test_upload.rb
@@ -18,7 +18,8 @@ class UploadTest < Test::Unit::TestCase
     @sha1 = Digest::SHA1.new
     @sha1_app = lambda do |env|
       input = env['rack.input']
-      resp = { :pos => input.pos, :size => input.stat.size }
+      resp = { :pos => input.pos, :size => input.size, :class => input.class }
+      @sha1.reset
       begin
         loop { @sha1.update(input.sysread(@bs)) }
       rescue EOFError
@@ -216,6 +217,22 @@ class UploadTest < Test::Unit::TestCase
     resp = `curl -isSfN -T#{tmp.path} http://#@addr:#@port/`
     assert $?.success?, 'curl ran OK'
     assert_match(%r!\b#{sha1}\b!, resp)
+    assert_match(/Tempfile/, resp)
+
+    # small StringIO path
+    assert(system("dd", "if=#{@random.path}", "of=#{tmp.path}",
+                        "bs=1024", "count=1"),
+           "dd #@random to #{tmp}")
+    sha1_re = %r!\b([a-f0-9]{40})\b!
+    sha1_out = `sha1sum #{tmp.path}`
+    assert $?.success?, 'sha1sum ran OK'
+
+    assert_match(sha1_re, sha1_out)
+    sha1 = sha1_re.match(sha1_out)[1]
+    resp = `curl -isSfN -T#{tmp.path} http://#@addr:#@port/`
+    assert $?.success?, 'curl ran OK'
+    assert_match(%r!\b#{sha1}\b!, resp)
+    assert_match(/StringIO/, resp)
   end
 
   private