about summary refs log tree commit homepage
path: root/t
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-12-08 22:02:45 +0000
committerEric Wong <normalperson@yhbt.net>2010-12-09 06:34:37 +0800
commit3b2fc62dadd3c90038c168849b33c4ca6df058da (patch)
tree2724ad66053bd63b433c69b3b7bf8821351f71eb /t
parent52f55529293e466a77090691d1fe06a7933c74a1 (diff)
downloadunicorn-3b2fc62dadd3c90038c168849b33c4ca6df058da.tar.gz
In case a request sends the header and buffer as one packet,
TeeInput relying on accounting info from StreamInput is harmful
as StreamInput will buffer in memory outside of TeeInput's
control.

This bug is triggered by calling env["rack.input"].size or
env["rack.input"].rewind before to read.
Diffstat (limited to 't')
-rw-r--r--t/rack-input-tests.ru21
-rwxr-xr-xt/t0100-rack-input-tests.sh124
2 files changed, 145 insertions, 0 deletions
diff --git a/t/rack-input-tests.ru b/t/rack-input-tests.ru
new file mode 100644
index 0000000..8c35630
--- /dev/null
+++ b/t/rack-input-tests.ru
@@ -0,0 +1,21 @@
+# SHA1 checksum generator
+require 'digest/sha1'
+use Rack::ContentLength
+cap = 16384
+app = lambda do |env|
+  /\A100-continue\z/i =~ env['HTTP_EXPECT'] and
+    return [ 100, {}, [] ]
+  digest = Digest::SHA1.new
+  input = env['rack.input']
+  input.size if env["PATH_INFO"] == "/size_first"
+  input.rewind if env["PATH_INFO"] == "/rewind_first"
+  if buf = input.read(rand(cap))
+    begin
+      raise "#{buf.size} > #{cap}" if buf.size > cap
+      digest.update(buf)
+    end while input.read(rand(cap), buf)
+  end
+
+  [ 200, {'Content-Type' => 'text/plain'}, [ digest.hexdigest << "\n" ] ]
+end
+run app
diff --git a/t/t0100-rack-input-tests.sh b/t/t0100-rack-input-tests.sh
new file mode 100755
index 0000000..1cd9279
--- /dev/null
+++ b/t/t0100-rack-input-tests.sh
@@ -0,0 +1,124 @@
+#!/bin/sh
+. ./test-lib.sh
+test -r random_blob || die "random_blob required, run with 'make $0'"
+
+t_plan 10 "rack.input read tests"
+
+t_begin "setup and startup" && {
+        rtmpfiles curl_out curl_err
+        unicorn_setup
+        unicorn -D rack-input-tests.ru -c $unicorn_config
+        blob_sha1=$(rsha1 < random_blob)
+        blob_size=$(wc -c < random_blob)
+        t_info "blob_sha1=$blob_sha1"
+        unicorn_wait_start
+}
+
+t_begin "corked identity request" && {
+        rm -f $tmp
+        (
+                cat $fifo > $tmp &
+                printf 'PUT / HTTP/1.0\r\n'
+                printf 'Content-Length: %d\r\n\r\n' $blob_size
+                cat random_blob
+                wait
+                echo ok > $ok
+        ) | ( sleep 1 && socat - TCP4:$listen > $fifo )
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test x"$(cat $ok)" = xok
+}
+
+t_begin "corked chunked request" && {
+        rm -f $tmp
+        (
+                cat $fifo > $tmp &
+                content-md5-put < random_blob
+                wait
+                echo ok > $ok
+        ) | ( sleep 1 && socat - TCP4:$listen > $fifo )
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test x"$(cat $ok)" = xok
+}
+
+t_begin "corked identity request (input#size first)" && {
+        rm -f $tmp
+        (
+                cat $fifo > $tmp &
+                printf 'PUT /size_first HTTP/1.0\r\n'
+                printf 'Content-Length: %d\r\n\r\n' $blob_size
+                cat random_blob
+                wait
+                echo ok > $ok
+        ) | ( sleep 1 && socat - TCP4:$listen > $fifo )
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test x"$(cat $ok)" = xok
+}
+
+t_begin "corked identity request (input#rewind first)" && {
+        rm -f $tmp
+        (
+                cat $fifo > $tmp &
+                printf 'PUT /rewind_first HTTP/1.0\r\n'
+                printf 'Content-Length: %d\r\n\r\n' $blob_size
+                cat random_blob
+                wait
+                echo ok > $ok
+        ) | ( sleep 1 && socat - TCP4:$listen > $fifo )
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test x"$(cat $ok)" = xok
+}
+
+t_begin "corked chunked request (input#size first)" && {
+        rm -f $tmp
+        (
+                cat $fifo > $tmp &
+                printf 'PUT /size_first HTTP/1.1\r\n'
+                printf 'Host: example.com\r\n'
+                printf 'Transfer-Encoding: chunked\r\n'
+                printf 'Trailer: Content-MD5\r\n'
+                printf '\r\n'
+                content-md5-put --no-headers < random_blob
+                wait
+                echo ok > $ok
+        ) | ( sleep 1 && socat - TCP4:$listen > $fifo )
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test x"$(cat $ok)" = xok
+}
+
+t_begin "corked chunked request (input#rewind first)" && {
+        rm -f $tmp
+        (
+                cat $fifo > $tmp &
+                printf 'PUT /rewind_first HTTP/1.1\r\n'
+                printf 'Host: example.com\r\n'
+                printf 'Transfer-Encoding: chunked\r\n'
+                printf 'Trailer: Content-MD5\r\n'
+                printf '\r\n'
+                content-md5-put --no-headers < random_blob
+                wait
+                echo ok > $ok
+        ) | ( sleep 1 && socat - TCP4:$listen > $fifo )
+        test 1 -eq $(grep $blob_sha1 $tmp |wc -l)
+        test x"$(cat $ok)" = xok
+}
+
+t_begin "regular request" && {
+        curl -sSf -T random_blob http://$listen/ > $curl_out 2> $curl_err
+        test x$blob_sha1 = x$(cat $curl_out)
+        test ! -s $curl_err
+}
+
+t_begin "chunked request" && {
+        curl -sSf -T- < random_blob http://$listen/ > $curl_out 2> $curl_err
+        test x$blob_sha1 = x$(cat $curl_out)
+        test ! -s $curl_err
+}
+
+dbgcat r_err
+
+t_begin "shutdown" && {
+        kill $unicorn_pid
+}
+
+t_done