From 4bd3e3aa1b92c75fafbb727820aeacae5e9bcb42 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Wed, 23 May 2007 19:09:37 +0000 Subject: [PATCH] Set RAW_POST_DATA when request parameters are parsed. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6823 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- .../lib/action_controller/cgi_process.rb | 2 +- actionpack/lib/action_controller/request.rb | 67 +++++++++---------- actionpack/test/controller/request_test.rb | 20 +++--- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/actionpack/lib/action_controller/cgi_process.rb b/actionpack/lib/action_controller/cgi_process.rb index dcfa39fc03..edb7fb38d8 100644 --- a/actionpack/lib/action_controller/cgi_process.rb +++ b/actionpack/lib/action_controller/cgi_process.rb @@ -72,7 +72,7 @@ module ActionController #:nodoc: 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 476f65a6dc..cdd35cc17b 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -231,11 +231,14 @@ module ActionController 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 @@ module ActionController 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 @@ module ActionController "backtrace" => e.backtrace } end + class << self def parse_query_parameters(query_string) return {} if query_string.blank? @@ -402,6 +395,24 @@ module ActionController 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 @@ module ActionController 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 4ec31b389c..4a43091823 100644 --- a/actionpack/test/controller/request_test.rb +++ b/actionpack/test/controller/request_test.rb @@ -708,9 +708,7 @@ class MultipartRequestParameterParsingTest < Test::Unit::TestCase 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 @@ end 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 @@ class XmlParamsParsingTest < Test::Unit::TestCase end def test_multiple_files - body = <<-end_body + person = parse_body(<<-end_body) David @@ -738,8 +734,6 @@ class XmlParamsParsingTest < Test::Unit::TestCase 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 @@ class XmlParamsParsingTest < Test::Unit::TestCase 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