about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2009-10-07 00:52:41 -0700
committerEric Wong <normalperson@yhbt.net>2009-10-07 01:00:47 -0700
commite825dd70a7e4a10f0dfba10610fd9d58a7b8e694 (patch)
tree5838e70434b8caf0a2543f455581069b89509747
parent438c99aec2d74489fa89b3a6c60d1fb41bb2f7e6 (diff)
downloadunicorn-e825dd70a7e4a10f0dfba10610fd9d58a7b8e694.tar.gz
We modified TeeInput to have read-in-full semantics in most
situations to suit existing apps and libraries (like Rails) that
don't check for and handle partial reads correctly.

The read-in-full semantics are needed by Rails because of this:
  https://rails.lighthouseapp.com/projects/8994/tickets/3343
-rw-r--r--test/unit/test_tee_input.rb46
1 files changed, 46 insertions, 0 deletions
diff --git a/test/unit/test_tee_input.rb b/test/unit/test_tee_input.rb
index a4dffaf..2bd6541 100644
--- a/test/unit/test_tee_input.rb
+++ b/test/unit/test_tee_input.rb
@@ -104,6 +104,22 @@ class TestTeeInput < Test::Unit::TestCase
     assert_equal Unicorn::Const::MAX_BODY + 1, ti.size
   end
 
+  def test_read_in_full_if_content_length
+    a, b = 300, 3
+    init_parser('.' * b, 300)
+    assert_equal 300, @parser.content_length
+    ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
+    pid = fork {
+      @wr.write('.' * 197)
+      sleep 1 # still a *potential* race here that would make the test moot...
+      @wr.write('.' * 100)
+    }
+    assert_equal a, ti.read(a).size
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    @wr.close
+  end
+
   def test_big_body_multi
     init_parser('.', Unicorn::Const::MAX_BODY + 1)
     ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
@@ -167,6 +183,36 @@ class TestTeeInput < Test::Unit::TestCase
     assert status.success?
   end
 
+  def test_chunked_ping_pong
+    @parser = Unicorn::HttpParser.new
+    @buf = "POST / HTTP/1.1\r\n" \
+           "Host: localhost\r\n" \
+           "Transfer-Encoding: chunked\r\n" \
+           "\r\n"
+    assert_equal @env, @parser.headers(@env, @buf)
+    assert_equal "", @buf
+    chunks = %w(aa bbb cccc dddd eeee)
+    rd, wr = IO.pipe
+
+    pid = fork {
+      chunks.each do |chunk|
+        rd.read(1) == "." and
+          @wr.write("#{'%x' % [ chunk.size]}\r\n#{chunk}\r\n")
+      end
+      @wr.write("0\r\n")
+    }
+    ti = Unicorn::TeeInput.new(@rd, @env, @parser, @buf)
+    assert_nil @parser.content_length
+    assert_nil ti.instance_eval { @size }
+    assert ! @parser.body_eof?
+    chunks.each do |chunk|
+      wr.write('.')
+      assert_equal chunk, ti.read(16384)
+    end
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+  end
+
 private
 
   def init_parser(body, size = nil)