Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions lib/net/http/generic_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -341,15 +341,15 @@ def encode_multipart_form_data(out, params, opt)
end
chunked_p = chunked?

buf = +''
buf = ''.b
params.each do |key, value, h={}|
key = quote_string(key, charset)
filename =
h.key?(:filename) ? h[:filename] :
value.respond_to?(:to_path) ? File.basename(value.to_path) :
nil

buf << "--#{boundary}\r\n"
buf << "--#{boundary}\r\n".b
if filename
filename = quote_string(filename, charset)
type = (h[:content_type] || 'application/octet-stream').to_s
Expand All @@ -358,10 +358,10 @@ def encode_multipart_form_data(out, params, opt)
end
buf << "Content-Disposition: form-data; " \
"name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
"Content-Type: #{type}\r\n\r\n"
"Content-Type: #{type}\r\n\r\n".b
if !out.respond_to?(:write) || !value.respond_to?(:read)
# if +out+ is not an IO or +value+ is not an IO
buf << (value.respond_to?(:read) ? value.read : value)
buf << (value.respond_to?(:read) ? value.read : value).b
elsif value.respond_to?(:size) && chunked_p
# if +out+ is an IO and +value+ is a File, use IO.copy_stream
flush_buffer(out, buf, chunked_p)
Expand All @@ -378,12 +378,12 @@ def encode_multipart_form_data(out, params, opt)
# HTML5 says, "The parts of the generated multipart/form-data
# resource that correspond to non-file fields must not have a
# Content-Type header specified."
buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
buf << (value.respond_to?(:read) ? value.read : value)
buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n".b
buf << (value.respond_to?(:read) ? value.read : value).b
end
buf << "\r\n"
end
buf << "--#{boundary}--\r\n"
buf << "--#{boundary}--\r\n".b
flush_buffer(out, buf, chunked_p)
out << "0\r\n\r\n" if chunked_p
end
Expand Down
40 changes: 40 additions & 0 deletions test/net/http/test_http.rb
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,46 @@ def test_set_form
}
end

def test_set_form_multipart_with_mixed_encodings
utf8 = "r\u{e4}ksm\u{f6}rg\u{e5}s".freeze
binary = "r\u{e4}kmacka".b.freeze
data = [
['utf8', StringIO.new(utf8)],
["bin\u{e4}ry", StringIO.new(binary)],
['file', utf8, filename: "f\u{e4}le"],
['file', binary, filename: 'binary']
]
expected = <<"__EOM__".b.gsub(/\n/, "\r\n")
--<boundary>
Content-Disposition: form-data; name="utf8"

r\u{e4}ksm\u{f6}rg\u{e5}s
--<boundary>
Content-Disposition: form-data; name="bin\u{e4}ry"

r\u{e4}kmacka
--<boundary>
Content-Disposition: form-data; name="file"; filename="f\u{e4}le"
Content-Type: application/octet-stream

r\u{e4}ksm\u{f6}rg\u{e5}s
--<boundary>
Content-Disposition: form-data; name="file"; filename="binary"
Content-Type: application/octet-stream

r\u{e4}kmacka
--<boundary>--
__EOM__
[false, true].each do |chunked|
start {|http|
@server.mount('/', lambda {|req, res| res.body = req.body })
_test_set_form_multipart(http, chunked, data, expected)
}
end
assert_equal(Encoding::UTF_8, utf8.encoding)
assert_equal(Encoding::BINARY, binary.encoding)
end

def _test_set_form_urlencoded(http, data)
req = Net::HTTP::Post.new('/')
req.set_form(data)
Expand Down