about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorzedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9>2006-03-19 05:18:11 +0000
committerzedshaw <zedshaw@19e92222-5c0b-0410-8929-a290d50e31e9>2006-03-19 05:18:11 +0000
commitebeac4b0312015147ef2319b27c903a791f122af (patch)
treee5d743a971f4fd9fc429d7df7b81d78a2c56bf25
parent28c6a99aee10fcdeecf5326f610455b79a3a9026 (diff)
downloadunicorn-ebeac4b0312015147ef2319b27c903a791f122af.tar.gz
git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@116 19e92222-5c0b-0410-8929-a290d50e31e9
-rw-r--r--Rakefile4
-rw-r--r--examples/simpletest.rb11
-rw-r--r--ext/http11/http11.c78
-rw-r--r--ext/http11/http11_parser.c51
-rw-r--r--ext/http11/http11_parser.h3
-rw-r--r--ext/http11/http11_parser.rl7
-rw-r--r--lib/mongrel.rb76
7 files changed, 128 insertions, 102 deletions
diff --git a/Rakefile b/Rakefile
index bb74d5b..4aeba02 100644
--- a/Rakefile
+++ b/Rakefile
@@ -65,7 +65,7 @@ task :package_win32 do
     spec.required_ruby_version = '>= 1.8.4'
 
     spec.add_dependency('win32-service', '>= 0.5.0')
-    spec.add_dependency('gem_plugin', ">= 0.2")
+    spec.add_dependency('gem_plugin', ">= 0.2.1")
 
     spec.extensions = []
     spec.platform = Gem::Platform::WIN32
@@ -79,11 +79,13 @@ task :install do
   sh %{sudo gem install pkg/mongrel-#{version}}
   sub_project("mongrel_status", :install)
   sub_project("mongrel_config", :install)
+  sub_project("mongrel_console", :install)
 end
 
 task :uninstall => [:clean] do
   sub_project("mongrel_status", :uninstall)
   sub_project("mongrel_config", :uninstall)
+  sub_project("mongrel_console", :uninstall)
   sh %{sudo gem uninstall mongrel}
   sub_project("gem_plugin", :uninstall)
 end
diff --git a/examples/simpletest.rb b/examples/simpletest.rb
index 438f69e..0d471b4 100644
--- a/examples/simpletest.rb
+++ b/examples/simpletest.rb
@@ -19,6 +19,16 @@ class SimpleHandler < Mongrel::HttpHandler
     end
 end
 
+class DumbHandler < Mongrel::HttpHandler
+  def process(request, response)
+    response.start do |head,out|
+      head["Content-Type"] = "text/html"
+      out.write("test")
+    end
+  end
+end
+
+
 if ARGV.length != 3
   STDERR.puts "usage:  simpletest.rb <host> <port> <docroot>"
   exit(1)
@@ -26,6 +36,7 @@ end
 
 h = Mongrel::HttpServer.new(ARGV[0], ARGV[1].to_i)
 h.register("/", SimpleHandler.new)
+h.register("/dumb", DumbHandler.new)
 h.register("/files", Mongrel::DirHandler.new(ARGV[2]))
 h.run
 
diff --git a/ext/http11/http11.c b/ext/http11/http11.c
index e69d185..1abec65 100644
--- a/ext/http11/http11.c
+++ b/ext/http11/http11.c
@@ -16,6 +16,21 @@ static VALUE global_request_method;
 static VALUE global_request_uri;
 static VALUE global_query_string;
 static VALUE global_http_version;
+static VALUE global_content_length;
+static VALUE global_http_content_length;
+static VALUE global_content_type;
+static VALUE global_http_content_type;
+static VALUE global_gateway_interface;
+static VALUE global_gateway_interface_value;
+static VALUE global_interface_value;
+static VALUE global_remote_address;
+static VALUE global_server_name;
+static VALUE global_server_port;
+static VALUE global_server_protocol;
+static VALUE global_server_protocol_value;
+static VALUE global_http_host;
+static VALUE global_mongrel_version;
+static VALUE global_server_software;
 
 
 void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen)
@@ -67,8 +82,34 @@ void http_version(void *data, const char *at, size_t length)
   rb_hash_aset(req, global_http_version, val);
 }
 
+/** Finalizes the request header to have a bunch of stuff that's
+    needed. */
 
+void header_done(void *data, const char *at, size_t length)
+{
+  VALUE req = (VALUE)data;
+  VALUE temp = Qnil;
+  VALUE host = Qnil;
+  VALUE port = Qnil;
+  char *colon = NULL;
+
+  rb_hash_aset(req, global_content_length, rb_hash_aref(req, global_http_content_length));
+  rb_hash_aset(req, global_content_type, rb_hash_aref(req, global_http_content_type));
+  rb_hash_aset(req, global_gateway_interface, global_gateway_interface_value);
+  if((temp = rb_hash_aref(req, global_http_host)) != Qnil) {
+    // ruby better close strings off with a '\0' dammit
+    colon = strchr(RSTRING(temp)->ptr, ':');
+    if(colon != NULL) {
+      rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING(temp)->ptr));
+      rb_hash_aset(req, global_server_port,
+                   rb_str_substr(temp, colon - RSTRING(temp)->ptr+1,
+                                 RSTRING(temp)->len));
+    }
+  }
 
+  rb_hash_aset(req, global_server_protocol, global_server_protocol_value);
+  rb_hash_aset(req, global_server_software, global_mongrel_version);
+}
 
 
 void HttpParser_free(void *data) {
@@ -90,7 +131,8 @@ VALUE HttpParser_alloc(VALUE klass)
     hp->request_uri = request_uri;
     hp->query_string = query_string;
     hp->http_version = http_version;
-    
+    hp->header_done = header_done;
+
     obj = Data_Wrap_Struct(klass, NULL, HttpParser_free, hp);
 
     return obj;
@@ -406,6 +448,8 @@ VALUE URIClassifier_resolve(VALUE self, VALUE uri)
   return result;
 }
 
+#define DEF_GLOBAL(name, val)   global_##name = rb_str_new2(val); rb_global_variable(&global_##name)
+
 
 void Init_http11()
 {
@@ -413,17 +457,27 @@ void Init_http11()
   mMongrel = rb_define_module("Mongrel");
   id_handler_map = rb_intern("@handler_map");
 
-  global_http_prefix = rb_str_new2("HTTP_");
-  rb_global_variable(&global_http_prefix);
-  global_request_method = rb_str_new2("REQUEST_METHOD");
-  rb_global_variable(&global_request_method);
-  global_request_uri = rb_str_new2("REQUEST_URI");
-  rb_global_variable(&global_request_uri);
-  global_query_string = rb_str_new2("QUERY_STRING");
-  rb_global_variable(&global_query_string);
-  global_http_version = rb_str_new2("HTTP_VERSION");
-  rb_global_variable(&global_http_version);
-  
+  DEF_GLOBAL(http_prefix, "HTTP_");
+  DEF_GLOBAL(request_method, "REQUEST_METHOD");
+  DEF_GLOBAL(request_uri, "REQUEST_URI");
+  DEF_GLOBAL(query_string, "QUERY_STRING");
+  DEF_GLOBAL(http_version, "HTTP_VERSION");
+  DEF_GLOBAL(content_length, "CONTENT_LENGTH");
+  DEF_GLOBAL(http_content_length, "HTTP_CONTENT_LENGTH");
+  DEF_GLOBAL(content_type, "CONTENT_TYPE");
+  DEF_GLOBAL(http_content_type, "HTTP_CONTENT_TYPE");
+  DEF_GLOBAL(gateway_interface, "GATEWAY_INTERFACE");
+  DEF_GLOBAL(gateway_interface_value, "CGI/1.2");
+  DEF_GLOBAL(remote_address, "REMOTE_ADDR");
+  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(mongrel_version, "Mongrel 0.3.12");
+  DEF_GLOBAL(server_software, "SERVER_SOFTWARE");
+
+
   cHttpParser = rb_define_class_under(mMongrel, "HttpParser", rb_cObject);
   rb_define_alloc_func(cHttpParser, HttpParser_alloc);
   rb_define_method(cHttpParser, "initialize", HttpParser_init,0);
diff --git a/ext/http11/http11_parser.c b/ext/http11/http11_parser.c
index c17d907..fcbfa31 100644
--- a/ext/http11/http11_parser.c
+++ b/ext/http11/http11_parser.c
@@ -9,7 +9,7 @@
 #define MARK(S,F) assert((F) - (S)->mark >= 0); (S)->mark = (F);
 
 /** machine **/
-#line 98 "ext/http11/http11_parser.rl"
+#line 101 "ext/http11/http11_parser.rl"
 
 
 /** Data **/
@@ -21,7 +21,7 @@ static int http_parser_first_final = 53;
 
 static int http_parser_error = 1;
 
-#line 102 "ext/http11/http11_parser.rl"
+#line 105 "ext/http11/http11_parser.rl"
 
 int http_parser_init(http_parser *parser)  {
     int cs = 0;
@@ -30,7 +30,7 @@ int http_parser_init(http_parser *parser)  {
         {
         cs = http_parser_start;
         }
-#line 106 "ext/http11/http11_parser.rl"
+#line 109 "ext/http11/http11_parser.rl"
     parser->cs = cs;
     parser->body_start = NULL;
     parser->content_len = 0;
@@ -305,14 +305,17 @@ case 21:
 tr40:
 #line 46 "ext/http11/http11_parser.rl"
         {
-               parser->body_start = p+1; goto _out53;
+               parser->body_start = p+1;
+               if(parser->header_done != NULL)
+                              parser->header_done(parser->data, p, 0);
+               goto _out53;
         }
         goto st53;
 st53:
         if ( ++p == pe )
                 goto _out53;
 case 53:
-#line 316 "ext/http11/http11_parser.c"
+#line 319 "ext/http11/http11_parser.c"
         goto st1;
 tr36:
 #line 16 "ext/http11/http11_parser.rl"
@@ -322,7 +325,7 @@ st22:
         if ( ++p == pe )
                 goto _out22;
 case 22:
-#line 326 "ext/http11/http11_parser.c"
+#line 329 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 33: goto st22;
                 case 58: goto tr32;
@@ -357,7 +360,7 @@ st23:
         if ( ++p == pe )
                 goto _out23;
 case 23:
-#line 361 "ext/http11/http11_parser.c"
+#line 364 "ext/http11/http11_parser.c"
         if ( (*p) == 13 )
                 goto tr49;
         goto tr52;
@@ -369,7 +372,7 @@ st24:
         if ( ++p == pe )
                 goto _out24;
 case 24:
-#line 373 "ext/http11/http11_parser.c"
+#line 376 "ext/http11/http11_parser.c"
         if ( (*p) == 13 )
                 goto tr49;
         goto st24;
@@ -381,7 +384,7 @@ st25:
         if ( ++p == pe )
                 goto _out25;
 case 25:
-#line 385 "ext/http11/http11_parser.c"
+#line 388 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 43: goto st25;
                 case 58: goto st26;
@@ -406,7 +409,7 @@ st26:
         if ( ++p == pe )
                 goto _out26;
 case 26:
-#line 410 "ext/http11/http11_parser.c"
+#line 413 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 32: goto tr34;
                 case 37: goto st27;
@@ -454,7 +457,7 @@ st29:
         if ( ++p == pe )
                 goto _out29;
 case 29:
-#line 458 "ext/http11/http11_parser.c"
+#line 461 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 32: goto tr34;
                 case 37: goto st31;
@@ -525,7 +528,7 @@ st33:
         if ( ++p == pe )
                 goto _out33;
 case 33:
-#line 529 "ext/http11/http11_parser.c"
+#line 532 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 32: goto tr46;
                 case 37: goto tr51;
@@ -547,7 +550,7 @@ st34:
         if ( ++p == pe )
                 goto _out34;
 case 34:
-#line 551 "ext/http11/http11_parser.c"
+#line 554 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 32: goto tr46;
                 case 37: goto st35;
@@ -569,7 +572,7 @@ st35:
         if ( ++p == pe )
                 goto _out35;
 case 35:
-#line 573 "ext/http11/http11_parser.c"
+#line 576 "ext/http11/http11_parser.c"
         if ( (*p) < 65 ) {
                 if ( 48 <= (*p) && (*p) <= 57 )
                         goto st36;
@@ -600,7 +603,7 @@ st37:
         if ( ++p == pe )
                 goto _out37;
 case 37:
-#line 604 "ext/http11/http11_parser.c"
+#line 607 "ext/http11/http11_parser.c"
         if ( (*p) == 69 )
                 goto st38;
         goto st1;
@@ -619,7 +622,7 @@ st39:
         if ( ++p == pe )
                 goto _out39;
 case 39:
-#line 623 "ext/http11/http11_parser.c"
+#line 626 "ext/http11/http11_parser.c"
         if ( (*p) == 69 )
                 goto st40;
         goto st1;
@@ -645,7 +648,7 @@ st42:
         if ( ++p == pe )
                 goto _out42;
 case 42:
-#line 649 "ext/http11/http11_parser.c"
+#line 652 "ext/http11/http11_parser.c"
         if ( (*p) == 80 )
                 goto st43;
         goto st1;
@@ -692,7 +695,7 @@ st48:
         if ( ++p == pe )
                 goto _out48;
 case 48:
-#line 696 "ext/http11/http11_parser.c"
+#line 699 "ext/http11/http11_parser.c"
         switch( (*p) ) {
                 case 79: goto st49;
                 case 85: goto st38;
@@ -713,7 +716,7 @@ st50:
         if ( ++p == pe )
                 goto _out50;
 case 50:
-#line 717 "ext/http11/http11_parser.c"
+#line 720 "ext/http11/http11_parser.c"
         if ( (*p) == 82 )
                 goto st51;
         goto st1;
@@ -788,15 +791,15 @@ case 52:
 
         _out: {}
         }
-#line 125 "ext/http11/http11_parser.rl"
+#line 128 "ext/http11/http11_parser.rl"
 
     parser->cs = cs;
     parser->nread = p - buffer;
     if(parser->body_start) {
         /* final \r\n combo encountered so stop right here */
         
-#line 799 "ext/http11/http11_parser.c"
-#line 131 "ext/http11/http11_parser.rl"
+#line 802 "ext/http11/http11_parser.c"
+#line 134 "ext/http11/http11_parser.rl"
         parser->nread++;
     }
 
@@ -808,8 +811,8 @@ int http_parser_finish(http_parser *parser)
         int cs = parser->cs;
 
         
-#line 812 "ext/http11/http11_parser.c"
-#line 142 "ext/http11/http11_parser.rl"
+#line 815 "ext/http11/http11_parser.c"
+#line 145 "ext/http11/http11_parser.rl"
 
         parser->cs = cs;
 
diff --git a/ext/http11/http11_parser.h b/ext/http11/http11_parser.h
index 6ca9cef..8d49a42 100644
--- a/ext/http11/http11_parser.h
+++ b/ext/http11/http11_parser.h
@@ -26,7 +26,8 @@ typedef struct http_parser {
   element_cb request_uri;
   element_cb query_string;
   element_cb http_version;
-
+  element_cb header_done;
+  
 } http_parser;
 
 int http_parser_init(http_parser *parser);
diff --git a/ext/http11/http11_parser.rl b/ext/http11/http11_parser.rl
index 1073d9f..8ef4acb 100644
--- a/ext/http11/http11_parser.rl
+++ b/ext/http11/http11_parser.rl
@@ -44,7 +44,10 @@
                               parser->http_version(parser->data, parser->mark, p - parser->mark);
         }
             action done {
-               parser->body_start = p+1; fbreak;
+               parser->body_start = p+1;
+               if(parser->header_done != NULL)
+                              parser->header_done(parser->data, p, 0);
+               fbreak;
         }
 
 
@@ -92,7 +95,7 @@
 
         message_header = field_name ":" field_value $0 CRLF >1;
         
-        Request = Request_Line (message_header)* ( CRLF @done );
+        Request = Request_Line (message_header)* ( CRLF @done);
 
         main := Request;
 }%%
diff --git a/lib/mongrel.rb b/lib/mongrel.rb
index 32f78bd..d5c994d 100644
--- a/lib/mongrel.rb
+++ b/lib/mongrel.rb
@@ -90,59 +90,20 @@ module Mongrel
   module Const
     # This is the part of the path after the SCRIPT_NAME.  URIClassifier will determine this.
     PATH_INFO="PATH_INFO"
+
     # This is the intial part that your handler is identified as by URIClassifier.
     SCRIPT_NAME="SCRIPT_NAME"
+
     # The original URI requested by the client.  Passed to URIClassifier to build PATH_INFO and SCRIPT_NAME.
     REQUEST_URI='REQUEST_URI'
 
-    # Content length (also available as HTTP_CONTENT_LENGTH).
-    CONTENT_LENGTH='CONTENT_LENGTH'
-
-    # Content length (also available as CONTENT_LENGTH).
-    HTTP_CONTENT_LENGTH='HTTP_CONTENT_LENGTH'
-
-    # Content type (also available as HTTP_CONTENT_TYPE).
-    CONTENT_TYPE='CONTENT_TYPE'
-
-    # Content type (also available as CONTENT_TYPE).
-    HTTP_CONTENT_TYPE='HTTP_CONTENT_TYPE'
-
-    # Gateway interface key in the HttpRequest parameters.
-    GATEWAY_INTERFACE='GATEWAY_INTERFACE'
-    # We claim to support CGI/1.2.
-    GATEWAY_INTERFACE_VALUE='CGI/1.2'
-
-    # Hosts remote IP address.  Mongrel does not do DNS resolves since that slows
-    # processing down considerably.
-    REMOTE_ADDR='REMOTE_ADDR'
-
-    # This is not given since Mongrel does not do DNS resolves.  It is only here for
-    # completeness for the CGI standard.
-    REMOTE_HOST='REMOTE_HOST'
-
-    # The name/host of our server as given by the HttpServer.new(host,port) call.
-    SERVER_NAME='SERVER_NAME'
-
-    # The port of our server as given by the HttpServer.new(host,port) call.
-    SERVER_PORT='SERVER_PORT'
-
-    # SERVER_NAME and SERVER_PORT come from this.
-    HTTP_HOST='HTTP_HOST'
-
-    # Official server protocol key in the HttpRequest parameters.
-    SERVER_PROTOCOL='SERVER_PROTOCOL'
-    # Mongrel claims to support HTTP/1.1.
-    SERVER_PROTOCOL_VALUE='HTTP/1.1'
-
-    # The actual server software being used (it's Mongrel man).
-    SERVER_SOFTWARE='SERVER_SOFTWARE'
-    
-    # Current Mongrel version (used for SERVER_SOFTWARE and other response headers).
-    MONGREL_VERSION='Mongrel 0.3.10'
+    MONGREL_VERSION="0.3.12"
 
     # The standard empty 404 response for bad requests.  Use Error4040Handler for custom stuff.
     ERROR_404_RESPONSE="HTTP/1.1 404 Not Found\r\nConnection: close\r\nServer: #{MONGREL_VERSION}\r\n\r\nNOT FOUND"
 
+    CONTENT_LENGTH="CONTENT_LENGTH"
+
     # A common header for indicating the server is too busy.  Not used yet.
     ERROR_503_RESPONSE="HTTP/1.1 503 Service Unavailable\r\n\r\nBUSY"
 
@@ -172,27 +133,14 @@ module Mongrel
       @body = initial_body || ""
       @params = params
       @socket = socket
-      
-      # fix up the CGI requirements
-      params[Const::CONTENT_LENGTH] = params[Const::HTTP_CONTENT_LENGTH] || 0
-      params[Const::CONTENT_TYPE] = params[Const::HTTP_CONTENT_TYPE] if params[Const::HTTP_CONTENT_TYPE]
-      params[Const::GATEWAY_INTERFACE]=Const::GATEWAY_INTERFACE_VALUE
-      params[Const::REMOTE_ADDR]=socket.peeraddr[3]
-      if params.has_key? Const::HTTP_HOST
-        host,port = params[Const::HTTP_HOST].split(":")
-        params[Const::SERVER_NAME]=host
-        params[Const::SERVER_PORT]=port || 80
-      end
-      params[Const::SERVER_PROTOCOL]=Const::SERVER_PROTOCOL_VALUE
-      params[Const::SERVER_SOFTWARE]=Const::MONGREL_VERSION
-
 
       # now, if the initial_body isn't long enough for the content length we have to fill it
       # TODO: adapt for big ass stuff by writing to a temp file
-      clen = params[Const::HTTP_CONTENT_LENGTH].to_i
+      clen = params[Const::CONTENT_LENGTH].to_i
       if @body.length < clen
         @body << @socket.read(clen - @body.length)
       end
+
     end
   end
 
@@ -354,9 +302,11 @@ module Mongrel
       # create the worker threads
       num_processors.times do |i|
         @processors << Thread.new do
+          parser = HttpParser.new
           while client = @req_queue.deq
             Timeout::timeout(timeout) do
-              process_client(client)
+              process_client(client, parser)
+              parser.reset
             end
           end
         end
@@ -370,14 +320,15 @@ module Mongrel
     # the performance just does not improve.  It is currently carefully constructed
     # to make sure that it gets the best possible performance, but anyone who
     # thinks they can make it faster is more than welcome to take a crack at it.
-    def process_client(client)
+    def process_client(client, parser)
       begin
-        parser = HttpParser.new
         params = {}
+
         data = client.readpartial(Const::CHUNK_SIZE)
 
         while true
           nread = parser.execute(params, data)
+
           if parser.finished?
             script_name, path_info, handler = @classifier.resolve(params[Const::REQUEST_URI])
 
@@ -385,6 +336,7 @@ module Mongrel
               params[Const::PATH_INFO] = path_info
               params[Const::SCRIPT_NAME] = script_name
               request = HttpRequest.new(params, data[nread ... data.length], client)
+
               response = HttpResponse.new(client)
               handler.process(request, response)
             else