From 64e45d14ba2d2ee2f96635939f1e3aed5911e792 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 6 Feb 2009 18:14:47 -0800 Subject: Use a persistent buffer with HttpRequest 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). --- lib/unicorn.rb | 16 +++++++--------- lib/unicorn/http_request.rb | 6 +++--- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'lib') 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 -- cgit v1.2.3-24-ge0c7