about summary refs log tree commit homepage
path: root/lib
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-02-06 18:14:47 -0800
committerEric Wong <normalperson@yhbt.net>2009-02-09 19:52:10 -0800
commit64e45d14ba2d2ee2f96635939f1e3aed5911e792 (patch)
tree6a514c358a69b68c0f37f74afb4c0ff24ff0cedb /lib
parent1fe42f0f8e7f0902eb02860fb098cbd73ddf4e5d (diff)
downloadunicorn-64e45d14ba2d2ee2f96635939f1e3aed5911e792.tar.gz
This allows us to avoid the overhead of allocating a new buffer
each and every time we call sysread (even when just parsing
headers for GET requests).
Diffstat (limited to 'lib')
-rw-r--r--lib/unicorn.rb16
-rw-r--r--lib/unicorn/http_request.rb6
2 files changed, 10 insertions, 12 deletions
diff --git a/lib/unicorn.rb b/lib/unicorn.rb
index bc940f0..aec69fb 100644
--- a/lib/unicorn.rb
+++ b/lib/unicorn.rb
@@ -83,7 +83,8 @@ module Unicorn
         parser, params = @parser, @params
         parser.reset
         params.clear
-        data = client.sysread(Const::CHUNK_SIZE)
+        buffer = @request.buffer
+        data = String.new(client.sysread(Const::CHUNK_SIZE, buffer))
         nparsed = 0
 
         # Assumption: nparsed will always be less since data will get filled with more
@@ -101,7 +102,7 @@ module Unicorn
             end
 
             raise "No REQUEST PATH" if !params[Const::REQUEST_PATH]
-
+
             params[Const::PATH_INFO] = params[Const::REQUEST_PATH]
             params[Const::SCRIPT_NAME] = ""
 
@@ -113,17 +114,14 @@ module Unicorn
             #  or other intermediary acting on behalf of the actual source client."
             params[Const::REMOTE_ADDR] = client.unicorn_peeraddr.last
 
-            # Select handlers that want more detailed request notification
             env = @request.consume(params, client) or break
             app_response = @app.call(env)
             HttpResponse.write(client, app_response)
-          break #done
+            break #done
           else
-            # Parser is not done, queue up more data to read and continue parsing
-            chunk = client.sysread(Const::CHUNK_SIZE)
-            break if !chunk or chunk.length == 0  # read failed, stop processing
-
-            data << chunk
+            # Parser is not done, queue up more data to read and continue
+            # parsing
+            data << client.sysread(Const::CHUNK_SIZE, buffer)
             if data.length >= Const::MAX_HEADER
               raise HttpParserError.new("HEADER is longer than allowed, aborting client early.")
             end
diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb
index aaa669a..61b84dd 100644
--- a/lib/unicorn/http_request.rb
+++ b/lib/unicorn/http_request.rb
@@ -6,12 +6,12 @@ module Unicorn
   # a StringIO object.  To be safe, you should assume it works like a file.
   #
   class HttpRequest
-    attr_reader :logger
+    attr_reader :logger, :buffer
 
-    # You don't really call this.  It's made for you.
     def initialize(logger)
       @logger = logger
       @tempfile = @body = nil
+      @buffer = ' ' * Const::CHUNK_SIZE # initial size, may grow
     end
 
     def reset
@@ -72,7 +72,7 @@ module Unicorn
     # It also expects any initial part of the body that has been read to be in
     # the @body already.  It will return true if successful and false if not.
     def read_body(socket, remain)
-      buf = ' ' # this string is reused for the lifetime of the loop
+      buf = @buffer
       while remain > 0
         begin
           socket.sysread(remain, buf) # short read if it's a socket