test/spec_multipart.rb in rack-1.5.5 vs test/spec_multipart.rb in rack-1.6.0.beta

- old
+ new

@@ -28,10 +28,48 @@ env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename)) params = Rack::Multipart.parse_multipart(env) params["text"].should.equal "contents" end + if "<3".respond_to?(:force_encoding) + should "set US_ASCII encoding based on charset" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename)) + params = Rack::Multipart.parse_multipart(env) + params["text"].encoding.should.equal Encoding::US_ASCII + + # I'm not 100% sure if making the param name encoding match the + # Content-Type charset is the right thing to do. We should revisit this. + params.keys.each do |key| + key.encoding.should.equal Encoding::US_ASCII + end + end + + should "set BINARY encoding on things without content type" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:none)) + params = Rack::Multipart.parse_multipart(env) + params["submit-name"].encoding.should.equal Encoding::UTF_8 + end + + should "set UTF8 encoding on names of things without content type" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:none)) + params = Rack::Multipart.parse_multipart(env) + params.keys.each do |key| + key.encoding.should.equal Encoding::UTF_8 + end + end + + should "default text to UTF8" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:text)) + params = Rack::Multipart.parse_multipart(env) + params['submit-name'].encoding.should.equal Encoding::UTF_8 + params['submit-name-with-content'].encoding.should.equal Encoding::UTF_8 + params.keys.each do |key| + key.encoding.should.equal Encoding::UTF_8 + end + end + end + should "raise RangeError if the key space is exhausted" do env = Rack::MockRequest.env_for("/", multipart_fixture(:content_type_and_no_filename)) old, Rack::Utils.key_space_limit = Rack::Utils.key_space_limit, 1 begin @@ -113,10 +151,22 @@ "Content-Type: text/plain\r\n" params["files"][:name].should.equal "files" params["files"][:tempfile].read.should.equal "contents" end + should "parse multipart upload with text file with no name field" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:filename_and_no_name)) + params = Rack::Multipart.parse_multipart(env) + params["file1.txt"][:type].should.equal "text/plain" + params["file1.txt"][:filename].should.equal "file1.txt" + params["file1.txt"][:head].should.equal "Content-Disposition: form-data; " + + "filename=\"file1.txt\"\r\n" + + "Content-Type: text/plain\r\n" + params["file1.txt"][:name].should.equal "file1.txt" + params["file1.txt"][:tempfile].read.should.equal "contents" + end + should "parse multipart upload with nested parameters" do env = Rack::MockRequest.env_for("/", multipart_fixture(:nested)) params = Rack::Multipart.parse_multipart(env) params["foo"]["submit-name"].should.equal "Larry" params["foo"]["files"][:type].should.equal "text/plain" @@ -164,10 +214,24 @@ "Content-Type: text/plain\r\n" params["files"][:name].should.equal "files" params["files"][:tempfile].read.should.equal "contents" end + should "parse multipart upload with filename with invalid characters" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:invalid_character)) + params = Rack::Multipart.parse_multipart(env) + params["files"][:type].should.equal "text/plain" + params["files"][:filename].should.match(/invalid/) + head = "Content-Disposition: form-data; " + + "name=\"files\"; filename=\"invalid\xC3.txt\"\r\n" + + "Content-Type: text/plain\r\n" + head = head.force_encoding("ASCII-8BIT") if head.respond_to?(:force_encoding) + params["files"][:head].should.equal head + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "contents" + end + should "not include file params if no file was selected" do env = Rack::MockRequest.env_for("/", multipart_fixture(:none)) params = Rack::Multipart.parse_multipart(env) params["submit-name"].should.equal "Larry" params["files"].should.equal nil @@ -180,10 +244,18 @@ params["foo"].should.equal "bar" params["files"].should.be.instance_of String params["files"].size.should.equal 252 end + should "parse multipart/mixed" do + env = Rack::MockRequest.env_for("/", multipart_fixture(:mixed_files)) + params = Rack::Utils::Multipart.parse_multipart(env) + params["foo"].should.equal "bar" + params["files"].should.be.instance_of String + params["files"].size.should.equal 252 + end + should "parse IE multipart upload and clean up filename" do env = Rack::MockRequest.env_for("/", multipart_fixture(:ie)) params = Rack::Multipart.parse_multipart(env) params["files"][:type].should.equal "text/plain" params["files"][:filename].should.equal "file1.txt" @@ -362,62 +434,28 @@ req.POST['file.path'].should.equal "/var/tmp/uploads/4/0001728414" req.POST['addresses'].should.not.equal nil end it "builds complete params with the chunk size of 16384 slicing exactly on boundary" do - begin - previous_limit = Rack::Utils.multipart_part_limit - Rack::Utils.multipart_part_limit = 256 + data = File.open(multipart_file("fail_16384_nofile"), 'rb') { |f| f.read }.gsub(/\n/, "\r\n") + options = { + "CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryWsY0GnpbI5U7ztzo", + "CONTENT_LENGTH" => data.length.to_s, + :input => StringIO.new(data) + } + env = Rack::MockRequest.env_for("/", options) + params = Rack::Multipart.parse_multipart(env) - data = File.open(multipart_file("fail_16384_nofile"), 'rb') { |f| f.read }.gsub(/\n/, "\r\n") - options = { - "CONTENT_TYPE" => "multipart/form-data; boundary=----WebKitFormBoundaryWsY0GnpbI5U7ztzo", - "CONTENT_LENGTH" => data.length.to_s, - :input => StringIO.new(data) - } - env = Rack::MockRequest.env_for("/", options) - params = Rack::Multipart.parse_multipart(env) - - params.should.not.equal nil - params.keys.should.include "AAAAAAAAAAAAAAAAAAA" - params["AAAAAAAAAAAAAAAAAAA"].keys.should.include "PLAPLAPLA_MEMMEMMEMM_ATTRATTRER" - params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"].keys.should.include "new" - params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"].keys.should.include "-2" - params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"].keys.should.include "ba_unit_id" - params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].should.equal "1017" - ensure - Rack::Utils.multipart_part_limit = previous_limit - end + params.should.not.equal nil + params.keys.should.include "AAAAAAAAAAAAAAAAAAA" + params["AAAAAAAAAAAAAAAAAAA"].keys.should.include "PLAPLAPLA_MEMMEMMEMM_ATTRATTRER" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"].keys.should.include "new" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"].keys.should.include "-2" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"].keys.should.include "ba_unit_id" + params["AAAAAAAAAAAAAAAAAAA"]["PLAPLAPLA_MEMMEMMEMM_ATTRATTRER"]["new"]["-2"]["ba_unit_id"].should.equal "1017" end - should "not reach a multi-part limit" do - begin - previous_limit = Rack::Utils.multipart_part_limit - Rack::Utils.multipart_part_limit = 4 - - env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields) - params = Rack::Multipart.parse_multipart(env) - params['reply'].should.equal 'yes' - params['to'].should.equal 'people' - params['from'].should.equal 'others' - ensure - Rack::Utils.multipart_part_limit = previous_limit - end - end - - should "reach a multipart limit" do - begin - previous_limit = Rack::Utils.multipart_part_limit - Rack::Utils.multipart_part_limit = 3 - - env = Rack::MockRequest.env_for '/', multipart_fixture(:three_files_three_fields) - lambda { Rack::Multipart.parse_multipart(env) }.should.raise(Rack::Multipart::MultipartLimitError) - ensure - Rack::Utils.multipart_part_limit = previous_limit - end - end - should "return nil if no UploadedFiles were used" do data = Rack::Multipart.build_multipart("people" => [{"submit-name" => "Larry", "files" => "contents"}]) data.should.equal nil end @@ -472,8 +510,32 @@ } env = Rack::MockRequest.env_for("/", options) params = Rack::Utils::Multipart.parse_multipart(env) params["file"][:filename].should.equal('long' * 100) + end + + should "support mixed case metadata" do + file = multipart_file(:text) + data = File.open(file, 'rb') { |io| io.read } + + type = "Multipart/Form-Data; Boundary=AaB03x" + length = data.respond_to?(:bytesize) ? data.bytesize : data.size + + e = { "CONTENT_TYPE" => type, + "CONTENT_LENGTH" => length.to_s, + :input => StringIO.new(data) } + + env = Rack::MockRequest.env_for("/", e) + params = Rack::Multipart.parse_multipart(env) + params["submit-name"].should.equal "Larry" + params["submit-name-with-content"].should.equal "Berry" + 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\n" + + "Content-Type: text/plain\r\n" + params["files"][:name].should.equal "files" + params["files"][:tempfile].read.should.equal "contents" end end