diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index dcfa39fc03e45ead96d3b6868c64b09fc423b966..edb7fb38d84bc5df73f73da31e3b02da20ed8c95 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -72,7 +72,7 @@ def query_parameters end def request_parameters - @request_parameters ||= self.class.parse_formatted_request_parameters(body, content_type_with_parameters, content_length, env) + @request_parameters ||= parse_formatted_request_parameters end def cookies diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index 476f65a6dce6fedba262e565286fd535075706b1..cdd35cc17b4de3f17a878c87b7607ab0b9cbc2ec 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -231,11 +231,14 @@ def relative_url_root end - # Receive the raw post data. - # This is useful for services such as REST, XMLRPC and SOAP - # which communicate over HTTP POST but don't use the traditional parameter format. + # Read the request body. This is useful for web services that need to + # work with raw requests directly. def raw_post - @env['RAW_POST_DATA'] ||= body.read + unless env.include? 'RAW_POST_DATA' + env['RAW_POST_DATA'] = body.read(content_length) + body.rewind if body.respond_to?(:rewind) + end + env['RAW_POST_DATA'] end # Returns both GET and POST parameters in a single hash. @@ -312,37 +315,26 @@ def content_type_from_legacy_post_data_format_header end end - - class << self - def extract_content_type_without_parameters(content_type_with_parameters) - $1.strip.downcase if content_type_with_parameters =~ /^([^,\;]*)/ - end - - def parse_formatted_request_parameters(body, content_type_with_parameters, content_length, env = {}) - content_length = content_length.to_i + def parse_formatted_request_parameters return {} if content_length.zero? - content_type, boundary = extract_multipart_boundary(content_type_with_parameters.to_s) + content_type, boundary = self.class.extract_multipart_boundary(content_type_with_parameters) return {} if content_type.blank? mime_type = Mime::Type.lookup(content_type) strategy = ActionController::Base.param_parsers[mime_type] # Only multipart form parsing expects a stream. - if strategy && strategy != :multipart_form - data = body.read(content_length) - body.rewind if body.respond_to?(:rewind) - body = data - end + body = raw_post if strategy && strategy != :multipart_form case strategy when Proc strategy.call(body) when :url_encoded_form - clean_up_ajax_request_body! body - parse_query_parameters(body) + self.class.clean_up_ajax_request_body! body + self.class.parse_query_parameters(body) when :multipart_form - parse_multipart_form_parameters(body, boundary, content_length, env) + self.class.parse_multipart_form_parameters(body, boundary, content_length, env) when :xml_simple, :xml_node body.blank? ? {} : Hash.from_xml(body).with_indifferent_access when :yaml @@ -359,6 +351,7 @@ def parse_formatted_request_parameters(body, content_type_with_parameters, conte "backtrace" => e.backtrace } end + class << self def parse_query_parameters(query_string) return {} if query_string.blank? @@ -402,6 +395,24 @@ def parse_multipart_form_parameters(body, boundary, content_length, env) parse_request_parameters(read_multipart(body, boundary, content_length, env)) end + def extract_multipart_boundary(content_type_with_parameters) + if content_type_with_parameters =~ MULTIPART_BOUNDARY + ['multipart/form-data', $1.dup] + else + extract_content_type_without_parameters(content_type_with_parameters) + end + end + + def extract_content_type_without_parameters(content_type_with_parameters) + $1.strip.downcase if content_type_with_parameters =~ /^([^,\;]*)/ + end + + def clean_up_ajax_request_body!(body) + body.chop! if body[-1] == 0 + body.gsub!(/&_=$/, '') + end + + private def get_typed_value(value) case value @@ -454,20 +465,6 @@ def original_filename MULTIPART_BOUNDARY = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n - def extract_multipart_boundary(content_type_with_parameters) - if content_type_with_parameters =~ MULTIPART_BOUNDARY - ['multipart/form-data', $1.dup] - else - extract_content_type_without_parameters(content_type_with_parameters) - end - end - - def clean_up_ajax_request_body!(body) - body.chop! if body[-1] == 0 - body.gsub!(/&_=$/, '') - end - - EOL = "\015\012" def read_multipart(body, boundary, content_length, env) diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/controller/request_test.rb index 4ec31b389c6d411a895a10f1b1b1c8a23b0b44f7..4a43091823d3779c75d2ad5e433e71849ee6e5e6 100644 --- a/actionpack/test/controller/request_test.rb +++ b/actionpack/test/controller/request_test.rb @@ -708,9 +708,7 @@ def test_mixed_files private def process(name) File.open(File.join(FIXTURE_PATH, name), 'rb') do |file| - content_length = file.stat.size.to_s - content_type = 'multipart/form-data, boundary=AaB03x' - ActionController::AbstractRequest.parse_formatted_request_parameters(file, content_type, content_length) + ActionController::AbstractRequest.parse_multipart_form_parameters(file, 'AaB03x', file.stat.size, {}) end end end @@ -718,9 +716,7 @@ def process(name) class XmlParamsParsingTest < Test::Unit::TestCase def test_single_file - body = "David#{Base64.encode64('ABC')}" - - person = ActionController::AbstractRequest.parse_formatted_request_parameters(StringIO.new(body), 'application/xml', body.size) + person = parse_body("David#{Base64.encode64('ABC')}") assert_equal "image/jpg", person['person']['avatar'].content_type assert_equal "me.jpg", person['person']['avatar'].original_filename @@ -728,7 +724,7 @@ def test_single_file end def test_multiple_files - body = <<-end_body + person = parse_body(<<-end_body) David @@ -738,8 +734,6 @@ def test_multiple_files end_body - person = ActionController::AbstractRequest.parse_formatted_request_parameters(StringIO.new(body), 'application/xml', body.size) - assert_equal "image/jpg", person['person']['avatars']['avatar'].first.content_type assert_equal "me.jpg", person['person']['avatars']['avatar'].first.original_filename assert_equal "ABC", person['person']['avatars']['avatar'].first.read @@ -748,4 +742,12 @@ def test_multiple_files assert_equal "you.gif", person['person']['avatars']['avatar'].last.original_filename assert_equal "DEF", person['person']['avatars']['avatar'].last.read end + + private + def parse_body(body) + env = { 'CONTENT_TYPE' => 'application/xml', + 'CONTENT_LENGTH' => body.size.to_s } + cgi = ActionController::Integration::Session::MockCGI.new(env, body) + ActionController::CgiRequest.new(cgi).request_parameters + end end