about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-03-22 20:39:33 -0700
committerEric Wong <normalperson@yhbt.net>2009-03-22 21:23:28 -0700
commit5d57a6f2525c3c1feea98d64e1caf2f32147cf7f (patch)
treea48e022f4daedd03c24c3fc6db5c49dfe4c35e61
parent1835c9e2e12e6674b52dd80e4598cad9c4ea1e84 (diff)
downloadunicorn-5d57a6f2525c3c1feea98d64e1caf2f32147cf7f.tar.gz
Ensure constants are used as hash keys and cleanup unused
constants.  This gives a 10-15% improvement with
test/benchmark/request.rb
-rw-r--r--lib/unicorn/const.rb34
-rw-r--r--lib/unicorn/http_request.rb66
2 files changed, 43 insertions, 57 deletions
diff --git a/lib/unicorn/const.rb b/lib/unicorn/const.rb
index 8f9e978..f3dabec 100644
--- a/lib/unicorn/const.rb
+++ b/lib/unicorn/const.rb
@@ -48,10 +48,6 @@ module Unicorn
   # the constant just refers to a string with the same contents.  Using these constants
   # gave about a 3% to 10% performance improvement over using the strings directly.
   # Symbols did not really improve things much compared to constants.
-  #
-  # While Unicorn does try to emulate the CGI/1.2 protocol, it does not use the REMOTE_IDENT,
-  # REMOTE_USER, or REMOTE_HOST parameters since those are either a security problem or
-  # too taxing on performance.
   module Const
     DATE="Date".freeze
 
@@ -61,10 +57,7 @@ module Unicorn
     # Request body
     HTTP_BODY="HTTP_BODY".freeze
 
-    # This is the initial part that your handler is identified as by URIClassifier.
-    SCRIPT_NAME="SCRIPT_NAME".freeze
-
-    # The original URI requested by the client.  Passed to URIClassifier to build PATH_INFO and SCRIPT_NAME.
+    # The original URI requested by the client.
     REQUEST_URI='REQUEST_URI'.freeze
     REQUEST_PATH='REQUEST_PATH'.freeze
     
@@ -76,14 +69,6 @@ module Unicorn
     DEFAULT_PORT = "8080".freeze    # default TCP listen port
     DEFAULT_LISTEN = "#{DEFAULT_HOST}:#{DEFAULT_PORT}".freeze
 
-    # 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: Unicorn #{UNICORN_VERSION}\r\n\r\nNOT FOUND".freeze
-
-    CONTENT_LENGTH="CONTENT_LENGTH".freeze
-
-    # 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".freeze
-
     # The basic max request size we'll try to read.
     CHUNK_SIZE=(16 * 1024)
 
@@ -95,22 +80,11 @@ module Unicorn
     MAX_BODY=MAX_HEADER
 
     # A frozen format for this is about 15% faster
-    CONTENT_TYPE = "Content-Type".freeze
-    LAST_MODIFIED = "Last-Modified".freeze
-    ETAG = "ETag".freeze
-    REQUEST_METHOD="REQUEST_METHOD".freeze
-    GET="GET".freeze
-    HEAD="HEAD".freeze
-    # ETag is based on the apache standard of hex mtime-size-inode (inode is 0 on win32)
-    ETAG_FORMAT="\"%x-%x-%x\"".freeze
-    LINE_END="\r\n".freeze
+    CONTENT_LENGTH="CONTENT_LENGTH".freeze
     REMOTE_ADDR="REMOTE_ADDR".freeze
     HTTP_X_FORWARDED_FOR="HTTP_X_FORWARDED_FOR".freeze
-    HTTP_IF_MODIFIED_SINCE="HTTP_IF_MODIFIED_SINCE".freeze
-    HTTP_IF_NONE_MATCH="HTTP_IF_NONE_MATCH".freeze
-    REDIRECT = "HTTP/1.1 302 Found\r\nLocation: %s\r\nConnection: close\r\n\r\n".freeze
-    HOST = "HOST".freeze
-    CONNECTION = "Connection".freeze
+    QUERY_STRING="QUERY_STRING".freeze
+    RACK_INPUT="rack.input".freeze
   end
 
 end
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index 411c56c..63d0f2e 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -13,6 +13,20 @@ module Unicorn
   #
   class HttpRequest
 
+     # default parameters we merge into the request env for Rack handlers
+     DEF_PARAMS = {
+       "rack.errors" => $stderr,
+       "rack.multiprocess" => true,
+       "rack.multithread" => false,
+       "rack.run_once" => false,
+       "rack.url_scheme" => "http",
+       "rack.version" => [0, 1],
+       "SCRIPT_NAME" => "",
+
+       # this is not in the Rack spec, but some apps may rely on it
+       "SERVER_SOFTWARE" => "Unicorn #{Const::UNICORN_VERSION}"
+     }.freeze
+
     def initialize(logger)
       @logger = logger
       @body = nil
@@ -52,17 +66,7 @@ module Unicorn
         nparsed = @parser.execute(@params, data, nparsed)
 
         if @parser.finished?
-          # 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
-
-          handle_body(socket) and return rack_env # success!
-          return nil # fail
+          return handle_body(socket) ? rack_env(socket) : nil
         else
           # Parser is not done, queue up more data to read and continue
           # parsing
@@ -123,23 +127,31 @@ module Unicorn
     # Returns an environment which is rackable:
     # http://rack.rubyforge.org/doc/files/SPEC.html
     # Based on Rack's old Mongrel handler.
-    def rack_env
+    def rack_env(socket)
+      # I'm considering enabling "unicorn.client".  It gives
+      # applications some rope to do some "interesting" things like
+      # replacing a worker with another process that has full control
+      # 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::REQUEST_PATH] ||=
-                           URI.parse(@params[Const::REQUEST_URI]).path
-      raise "No REQUEST PATH" unless @params[Const::REQUEST_PATH]
-
-      @params["QUERY_STRING"] ||= ''
-      @params.update({ "rack.version" => [0,1],
-                      "rack.input" => @body,
-                      "rack.errors" => $stderr,
-                      "rack.multithread" => false,
-                      "rack.multiprocess" => true,
-                      "rack.run_once" => false,
-                      "rack.url_scheme" => "http",
-                      Const::PATH_INFO => @params[Const::REQUEST_PATH],
-                      Const::SCRIPT_NAME => "",
-                    })
+      @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
 
     # Does the heavy lifting of properly reading the larger body requests in