From b43309328a4a4c1f6fda6db40a4a86a3c8d643fc Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 16:01:42 -0700 Subject: Ruby 1.9 compat: ensure binary encoding for post body parsing --- .../lib/action_controller/cgi_ext/stdinput.rb | 1 + actionpack/lib/action_controller/cgi_process.rb | 1 + actionpack/lib/action_controller/integration.rb | 4 ++++ actionpack/lib/action_controller/request.rb | 28 +++++++++++++--------- actionpack/lib/action_controller/test_process.rb | 3 ++- actionpack/test/controller/test_test.rb | 20 ++++++++++++---- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/actionpack/lib/action_controller/cgi_ext/stdinput.rb b/actionpack/lib/action_controller/cgi_ext/stdinput.rb index b0ca63ef2f..5e9b6784af 100644 --- a/actionpack/lib/action_controller/cgi_ext/stdinput.rb +++ b/actionpack/lib/action_controller/cgi_ext/stdinput.rb @@ -16,6 +16,7 @@ module ActionController def initialize_with_stdinput(type = nil, stdinput = $stdin) @stdinput = stdinput + @stdinput.set_encoding(Encoding::BINARY) if @stdinput.respond_to?(:set_encoding) initialize_without_stdinput(type || 'query') end end diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index b529db8af4..7e58c98bf2 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -65,6 +65,7 @@ module ActionController #:nodoc: # variable is already set, wrap it in a StringIO. def body if raw_post = env['RAW_POST_DATA'] + raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding) StringIO.new(raw_post) else @cgi.stdinput diff --git a/actionpack/lib/action_controller/integration.rb b/actionpack/lib/action_controller/integration.rb index a4bbee9c54..f0fc1945a9 100644 --- a/actionpack/lib/action_controller/integration.rb +++ b/actionpack/lib/action_controller/integration.rb @@ -228,6 +228,8 @@ module ActionController super + stdinput.set_encoding(Encoding::BINARY) if stdinput.respond_to?(:set_encoding) + stdinput.force_encoding(Encoding::BINARY) if stdinput.respond_to?(:force_encoding) @stdinput = stdinput.is_a?(IO) ? stdinput : StringIO.new(stdinput || '') end end @@ -382,6 +384,8 @@ module ActionController multipart_requestify(params).map do |key, value| if value.respond_to?(:original_filename) File.open(value.path) do |f| + f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding) + <<-EOF --#{boundary}\r Content-Disposition: form-data; name="#{key}"; filename="#{CGI.escape(value.original_filename)}"\r diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index d5ecbd9d29..a35b904194 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -466,8 +466,8 @@ EOM parser.result end - def parse_multipart_form_parameters(body, boundary, content_length, env) - parse_request_parameters(read_multipart(body, boundary, content_length, env)) + def parse_multipart_form_parameters(body, boundary, body_size, env) + parse_request_parameters(read_multipart(body, boundary, body_size, env)) end def extract_multipart_boundary(content_type_with_parameters) @@ -519,7 +519,7 @@ EOM EOL = "\015\012" - def read_multipart(body, boundary, content_length, env) + def read_multipart(body, boundary, body_size, env) params = Hash.new([]) boundary = "--" + boundary quoted_boundary = Regexp.quote(boundary) @@ -529,8 +529,14 @@ EOM # start multipart/form-data body.binmode if defined? body.binmode + case body + when File + body.set_encoding(Encoding::BINARY) if body.respond_to?(:set_encoding) + when StringIO + body.string.force_encoding(Encoding::BINARY) if body.string.respond_to?(:force_encoding) + end boundary_size = boundary.size + EOL.size - content_length -= boundary_size + body_size -= boundary_size status = body.read(boundary_size) if nil == status raise EOFError, "no content body" @@ -541,7 +547,7 @@ EOM loop do head = nil content = - if 10240 < content_length + if 10240 < body_size UploadedTempfile.new("CGI") else UploadedStringIO.new @@ -563,24 +569,24 @@ EOM buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = "" end - c = if bufsize < content_length + c = if bufsize < body_size body.read(bufsize) else - body.read(content_length) + body.read(body_size) end if c.nil? || c.empty? raise EOFError, "bad content body" end buf.concat(c) - content_length -= c.size + body_size -= c.size end buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{quoted_boundary}([\r\n]{1,2}|--)/n) do content.print $1 if "--" == $2 - content_length = -1 + body_size = -1 end - boundary_end = $2.dup + boundary_end = $2.dup "" end @@ -607,7 +613,7 @@ EOM else params[name] = [content] end - break if content_length == -1 + break if body_size == -1 end raise EOFError, "bad boundary end of body part" unless boundary_end=~/--/ diff --git a/actionpack/lib/action_controller/test_process.rb b/actionpack/lib/action_controller/test_process.rb index dcb6cdf4ca..f03ed5b2a7 100644 --- a/actionpack/lib/action_controller/test_process.rb +++ b/actionpack/lib/action_controller/test_process.rb @@ -49,7 +49,7 @@ module ActionController #:nodoc: # Either the RAW_POST_DATA environment variable or the URL-encoded request # parameters. def raw_post - env['RAW_POST_DATA'] ||= url_encoded_request_parameters + env['RAW_POST_DATA'] ||= returning(url_encoded_request_parameters) { |b| b.force_encoding(Encoding::BINARY) if b.respond_to?(:force_encoding) } end def port=(number) @@ -340,6 +340,7 @@ module ActionController #:nodoc: @content_type = content_type @original_filename = path.sub(/^.*#{File::SEPARATOR}([^#{File::SEPARATOR}]+)$/) { $1 } @tempfile = Tempfile.new(@original_filename) + @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding) @tempfile.binmode if binary FileUtils.copy_file(path, @tempfile.path) end diff --git a/actionpack/test/controller/test_test.rb b/actionpack/test/controller/test_test.rb index ba6c7f4299..38898a1f75 100644 --- a/actionpack/test/controller/test_test.rb +++ b/actionpack/test/controller/test_test.rb @@ -511,16 +511,26 @@ XML FILES_DIR = File.dirname(__FILE__) + '/../fixtures/multipart' + if RUBY_VERSION < '1.9' + READ_BINARY = 'rb' + READ_PLAIN = 'r' + else + READ_BINARY = 'rb:binary' + READ_PLAIN = 'r:binary' + end + def test_test_uploaded_file filename = 'mona_lisa.jpg' path = "#{FILES_DIR}/#{filename}" content_type = 'image/png' + expected = File.read(path) + expected.force_encoding(Encoding::BINARY) if expected.respond_to?(:force_encoding) file = ActionController::TestUploadedFile.new(path, content_type) assert_equal filename, file.original_filename assert_equal content_type, file.content_type assert_equal file.path, file.local_path - assert_equal File.read(path), file.read + assert_equal expected, file.read end def test_test_uploaded_file_with_binary @@ -529,10 +539,10 @@ XML content_type = 'image/png' binary_uploaded_file = ActionController::TestUploadedFile.new(path, content_type, :binary) - assert_equal File.open(path, 'rb').read, binary_uploaded_file.read + assert_equal File.open(path, READ_BINARY).read, binary_uploaded_file.read plain_uploaded_file = ActionController::TestUploadedFile.new(path, content_type) - assert_equal File.open(path, 'r').read, plain_uploaded_file.read + assert_equal File.open(path, READ_PLAIN).read, plain_uploaded_file.read end def test_fixture_file_upload_with_binary @@ -541,10 +551,10 @@ XML content_type = 'image/jpg' binary_file_upload = fixture_file_upload(path, content_type, :binary) - assert_equal File.open(path, 'rb').read, binary_file_upload.read + assert_equal File.open(path, READ_BINARY).read, binary_file_upload.read plain_file_upload = fixture_file_upload(path, content_type) - assert_equal File.open(path, 'r').read, plain_file_upload.read + assert_equal File.open(path, READ_PLAIN).read, plain_file_upload.read end def test_fixture_file_upload -- cgit v1.2.3