From 6eb46e422f4b2ba98c795fca5e18e7262c0c688e Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 8 Oct 2010 23:44:23 +0000 Subject: add PrereadInput middleware to get around TeeInput This may be useful for some apps that wish to drain the body before acquiring an app-wide lock. Maybe it's more useful with Rainbows!... --- lib/unicorn/preread_input.rb | 30 +++++++++++++++++++++++++++ t/preread_input.ru | 17 ++++++++++++++++ t/t9000-preread-input.sh | 48 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 lib/unicorn/preread_input.rb create mode 100644 t/preread_input.ru create mode 100755 t/t9000-preread-input.sh diff --git a/lib/unicorn/preread_input.rb b/lib/unicorn/preread_input.rb new file mode 100644 index 0000000..ec83cb2 --- /dev/null +++ b/lib/unicorn/preread_input.rb @@ -0,0 +1,30 @@ +# -*- encoding: binary -*- + +module Unicorn +# This middleware is used to ensure input is buffered to memory +# or disk (depending on size) before the application is dispatched +# by entirely consuming it (from TeeInput) beforehand. +# +# Usage (in config.ru): +# +# require 'unicorn/preread_input' +# if defined?(Unicorn) +# use Unicorn::PrereadInput +# end +# run YourApp.new +class PrereadInput + def initialize(app) + @app = app + end + + def call(env) + buf = "" + input = env["rack.input"] + if buf = input.read(16384) + true while input.read(16384, buf) + input.rewind + end + @app.call(env) + end +end +end diff --git a/t/preread_input.ru b/t/preread_input.ru new file mode 100644 index 0000000..79685c4 --- /dev/null +++ b/t/preread_input.ru @@ -0,0 +1,17 @@ +#\-E none +require 'digest/sha1' +require 'unicorn/preread_input' +use Rack::ContentLength +use Rack::ContentType, "text/plain" +use Unicorn::PrereadInput +nr = 0 +run lambda { |env| + $stderr.write "app dispatch: #{nr += 1}\n" + input = env["rack.input"] + dig = Digest::SHA1.new + while buf = input.read(16384) + dig.update(buf) + end + + [ 200, {}, [ "#{dig.hexdigest}\n" ] ] +} diff --git a/t/t9000-preread-input.sh b/t/t9000-preread-input.sh new file mode 100755 index 0000000..b9da05e --- /dev/null +++ b/t/t9000-preread-input.sh @@ -0,0 +1,48 @@ +#!/bin/sh +. ./test-lib.sh +t_plan 9 "PrereadInput middleware tests" + +t_begin "setup and start" && { + random_blob_sha1=$(rsha1 < random_blob) + unicorn_setup + unicorn -D -c $unicorn_config preread_input.ru + unicorn_wait_start +} + +t_begin "single identity request" && { + curl -sSf -T random_blob http://$listen/ > $tmp +} + +t_begin "sha1 matches" && { + test x"$(cat $tmp)" = x"$random_blob_sha1" +} + +t_begin "single chunked request" && { + curl -sSf -T- < random_blob http://$listen/ > $tmp +} + +t_begin "sha1 matches" && { + test x"$(cat $tmp)" = x"$random_blob_sha1" +} + +t_begin "app only dispatched twice" && { + test 2 -eq "$(grep 'app dispatch:' < $r_err | wc -l )" +} + +t_begin "aborted chunked request" && { + rm -f $tmp + curl -sSf -T- < $fifo http://$listen/ > $tmp & + curl_pid=$! + kill -9 $curl_pid + wait +} + +t_begin "app only dispatched twice" && { + test 2 -eq "$(grep 'app dispatch:' < $r_err | wc -l )" +} + +t_begin "killing succeeds" && { + kill -QUIT $unicorn_pid +} + +t_done -- cgit v1.2.3-24-ge0c7