From 94e1c91947fccc291625dcdb106f37a3e36f7f2c Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Tue, 13 Jan 2009 18:21:51 -0600 Subject: [PATCH] Add tests for multipart uploads. Also ensure multipart parser tries to rewind the input stream. --- lib/rack/request.rb | 8 +++++++- lib/rack/utils.rb | 7 +++++++ test/multipart/text_file | 10 ++++++++++ test/spec_rack_utils.rb | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletions(-) create mode 100644 test/multipart/text_file diff --git a/lib/rack/request.rb b/lib/rack/request.rb index 4447d03..4a0c85b 100644 --- a/lib/rack/request.rb +++ b/lib/rack/request.rb @@ -121,7 +121,13 @@ module Rack Utils::Multipart.parse_multipart(env) @env["rack.request.form_vars"] = @env["rack.input"].read @env["rack.request.form_hash"] = Utils.parse_query(@env["rack.request.form_vars"]) - @env["rack.input"].rewind if @env["rack.input"].respond_to?(:rewind) + + begin + @env["rack.input"].rewind if @env["rack.input"].respond_to?(:rewind) + rescue Errno::ESPIPE + # Handles exceptions raised by input streams that cannot be rewound + # such as when using plain CGI under Apache + end end @env["rack.request.form_hash"] else diff --git a/lib/rack/utils.rb b/lib/rack/utils.rb index 5a7f87d..03009a9 100644 --- a/lib/rack/utils.rb +++ b/lib/rack/utils.rb @@ -311,6 +311,13 @@ module Rack break if buf.empty? || content_length == -1 } + begin + input.rewind if input.respond_to?(:rewind) + rescue Errno::ESPIPE + # Handles exceptions raised by input streams that cannot be rewound + # such as when using plain CGI under Apache + end + params end end diff --git a/test/multipart/text_file b/test/multipart/text_file new file mode 100644 index 0000000..b83d382 --- /dev/null +++ b/test/multipart/text_file @@ -0,0 +1,10 @@ +--AaB03x +Content-Disposition: form-data; name="submit-name" + +Larry +--AaB03x +Content-Disposition: form-data; name="files"; filename="file1.txt" +Content-Type: text/plain + +contents +--AaB03x-- \ No newline at end of file diff --git a/test/spec_rack_utils.rb b/test/spec_rack_utils.rb index 82ac0da..8bbd9fe 100644 --- a/test/spec_rack_utils.rb +++ b/test/spec_rack_utils.rb @@ -150,3 +150,44 @@ context "Rack::Utils::Context" do r4.body.should.equal r5.body end end + +context "Rack::Utils::Multipart" do + specify "should return nil if content type is not multipart" do + env = Rack::MockRequest.env_for("/", + "CONTENT_TYPE" => 'application/x-www-form-urlencoded') + Rack::Utils::Multipart.parse_multipart(env).should.equal nil + end + + specify "should parse multipart upload with text file" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:text_file)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["files"][:type].should.equal "text/plain" + params["files"][:filename].should.equal "file1.txt" + params["files"][:head].should.equal "Content-Disposition: form-data; name=\"files\"; filename=\"file1.txt\"\r\nContent-Type: text/plain\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "contents" + end + + specify "rewinds input after parsing upload" do + options = multipart_fixture(:text_file) + input = options[:input] + env = Rack::MockRequest.env_for("/", options) + params = Rack::Utils::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + input.read.length.should.equal 197 + end + + private + def multipart_fixture(name) + file = File.join(File.dirname(__FILE__), "multipart", name.to_s) + data = File.read(file) + + type = "multipart/form-data; boundary=AaB03x" + length = data.length.to_s + + { "CONTENT_TYPE" => type, + "CONTENT_LENGTH" => length, + :input => StringIO.new(data) } + end +end -- 1.6.0.4