From 8ca2d34df19ed7802a59bdedb78e2261487c064c Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 23 Apr 2009 18:35:26 -0700 Subject: Fix data corruption with small uploads via browsers StringIO.new(partial_body) does not update the offset for new writes. So instead create the StringIO object and then syswrite to it and try to follow the same code path used by large uploads which use Tempfiles. --- lib/unicorn/http_request.rb | 13 ++++--------- test/unit/test_upload.rb | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/unicorn/http_request.rb b/lib/unicorn/http_request.rb index a3a1d4d..399aee5 100644 --- a/lib/unicorn/http_request.rb +++ b/lib/unicorn/http_request.rb @@ -87,15 +87,10 @@ module Unicorn remain = content_length - http_body.length # must read more data to complete body - if remain < Const::MAX_BODY - # small body, just use that - @body = StringIO.new(http_body) - else # huge body, put it in a tempfile - @body = Tempfile.new(Const::UNICORN_TMP_BASE) - @body.binmode - @body.sync = true - @body.syswrite(http_body) - end + @body = remain < Const::MAX_BODY ? StringIO.new : Tempfile.new('') + @body.binmode + @body.sync = true + @body.syswrite(http_body) # Some clients (like FF1.0) report 0 for body and then send a body. # This will probably truncate them but at least the request goes through diff --git a/test/unit/test_upload.rb b/test/unit/test_upload.rb index 58058f1..86b6c6c 100644 --- a/test/unit/test_upload.rb +++ b/test/unit/test_upload.rb @@ -50,6 +50,29 @@ class UploadTest < Test::Unit::TestCase assert_equal @sha1.hexdigest, resp[:sha1] end + def test_put_trickle_small + @count, @bs = 2, 128 + start_server(@sha1_app) + assert_equal 256, length + sock = TCPSocket.new(@addr, @port) + hdr = "PUT / HTTP/1.0\r\nContent-Length: #{length}\r\n\r\n" + @count.times do + buf = @random.sysread(@bs) + @sha1.update(buf) + hdr << buf + sock.syswrite(hdr) + hdr = '' + sleep 0.6 + end + read = sock.read.split(/\r\n/) + assert_equal "HTTP/1.1 200 OK", read[0] + resp = eval(read.grep(/^X-Resp: /).first.sub!(/X-Resp: /, '')) + assert_equal length, resp[:size] + assert_equal 0, resp[:pos] + assert_equal @sha1.hexdigest, resp[:sha1] + assert_equal StringIO, resp[:class] + end + def test_tempfile_unlinked spew_path = lambda do |env| if orig = env['HTTP_X_OLD_PATH'] -- cgit v1.2.3-24-ge0c7 From 574d4553c63fdec4ef7ef8ac873db868021b4ba5 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Thu, 23 Apr 2009 18:41:08 -0700 Subject: unicorn 0.5.4 --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 6ac1c83..8eeb334 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +v0.5.4 - fix data corruption with some small uploads (not curl) v0.5.3 - fix 100% CPU usage when idle, small cleanups v0.5.2 - force Status: header for compat, small cleanups v0.5.1 - exit correctly on INT/TERM, QUIT is still recommended, however -- cgit v1.2.3-24-ge0c7