From c8e46fcb007a8599cac1b3861744669b1eab9406 Mon Sep 17 00:00:00 2001 From: why Date: Tue, 11 Apr 2006 01:46:13 +0000 Subject: Support large file uploads, moving them into a Tempfile should they cross the MAX_BODY threshold. The only change here really is that HttpRequest#body is now an IO object rather than a string. I changed the various handlers to support this. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/trunk@157 19e92222-5c0b-0410-8929-a290d50e31e9 --- examples/camping/blog.rb | 2 +- lib/mongrel.rb | 28 ++++++++++++++++++++++------ lib/mongrel/camping.rb | 3 +-- lib/mongrel/cgi.rb | 2 +- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/examples/camping/blog.rb b/examples/camping/blog.rb index 18732a4..81a87da 100755 --- a/examples/camping/blog.rb +++ b/examples/camping/blog.rb @@ -281,7 +281,7 @@ if __FILE__ == $0 # Use the Configurator as an example rather than Mongrel::Camping.start config = Mongrel::Configurator.new :host => "0.0.0.0" do listener :port => 3002 do - uri "/blog", :handler => CampingHandler.new(Blog) + uri "/blog", :handler => Mongrel::Camping::CampingHandler.new(Blog) uri "/favicon", :handler => Mongrel::Error404Handler.new("") trap("INT") { stop } run diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 228fd9f..0a069fb 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -1,5 +1,6 @@ require 'socket' require 'http11' +require 'tempfile' require 'thread' require 'stringio' require 'mongrel/cgi' @@ -125,6 +126,9 @@ module Mongrel # this, but we'd also like to do this as well. MAX_HEADER=1024 * (80 + 32) + # Maximum request body size before it is moved out of memory and into a tempfile for reading. + MAX_BODY=MAX_HEADER + # A frozen format for this is about 15% faster STATUS_FORMAT = "HTTP/1.1 %d %s\r\nContent-Length: %d\r\nConnection: close\r\n".freeze CONTENT_TYPE = "Content-Type".freeze @@ -164,13 +168,26 @@ module Mongrel @params = params @socket = socket - # 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 + # if the body size is too large, move into a tempfile clen = params[Const::CONTENT_LENGTH].to_i - if @body.length < clen - @body << @socket.read(clen - @body.length) + if clen > Const::MAX_BODY + tmpf = Tempfile.new(self.class.name) + tmpf.binmode + tmpf.write(@body) + # TODO: throw an error if content-length doesn't match?? + while clen > 0 + readlen = clen < Const::CHUNK_SIZE ? clen : Const::CHUNK_SIZE + tmpf.write(@socket.read(readlen)) + clen -= readlen + end + tmpf.rewind + @body = tmpf + else + if @body.length < clen + @body << @socket.read(clen - @body.length) + end + @body = StringIO.new(@body) end - end def self.escape(s) @@ -205,7 +222,6 @@ module Mongrel return params end - end diff --git a/lib/mongrel/camping.rb b/lib/mongrel/camping.rb index 5e42c9f..e305a9b 100644 --- a/lib/mongrel/camping.rb +++ b/lib/mongrel/camping.rb @@ -32,8 +32,7 @@ module Mongrel end def process(request, response) - req = StringIO.new(request.body) - controller = @klass.run(req, request.params) + controller = @klass.run(request.body, request.params) sendfile, clength = nil response.status = controller.status controller.headers.each do |k, v| diff --git a/lib/mongrel/cgi.rb b/lib/mongrel/cgi.rb index 14982e0..7e93ba3 100644 --- a/lib/mongrel/cgi.rb +++ b/lib/mongrel/cgi.rb @@ -35,7 +35,7 @@ module Mongrel @request = request @response = response @args = *args - @input = StringIO.new(request.body) + @input = request.body @head = {} @out_called = false super(*args) -- cgit v1.2.3-24-ge0c7