diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2007-05-19 21:34:36 +0000 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2007-05-19 21:34:36 +0000 |
commit | 055ff9f41844a90080ec12f2e632ff755f67f097 (patch) | |
tree | 7bd77e9d4545b627380ca699725c0cb849b28236 | |
parent | f52021ddd2f1a1f38ec9c6ee8d58ee92cbe7e5e8 (diff) | |
download | rails-055ff9f41844a90080ec12f2e632ff755f67f097.tar.gz rails-055ff9f41844a90080ec12f2e632ff755f67f097.tar.bz2 rails-055ff9f41844a90080ec12f2e632ff755f67f097.zip |
Fix incorrent content type lookup in request parsing. Closes #8407.
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@6786 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
-rwxr-xr-x | actionpack/lib/action_controller/request.rb | 62 | ||||
-rwxr-xr-x | actionpack/test/controller/cgi_test.rb | 18 |
2 files changed, 52 insertions, 28 deletions
diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index 345832d43a..0dfc4a91d0 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -63,32 +63,14 @@ module ActionController @content_length ||= env['CONTENT_LENGTH'].to_i end - def content_type_with_parameters - @content_type_with_parameters ||= env['CONTENT_TYPE'].to_s - end - - # Determine whether the body of a HTTP call is URL-encoded (default) - # or matches one of the registered param_parsers. + # The MIME type of the HTTP request, such as Mime::XML. # # For backward compatibility, the post format is extracted from the # X-Post-Data-Format HTTP header if present. def content_type @content_type ||= - begin - # Receive header sans any charset information. - content_type = content_type_with_parameters.sub(/\s*\;.*$/, '').strip.downcase - - if x_post_format = @env['HTTP_X_POST_DATA_FORMAT'] - case x_post_format.to_s.downcase - when 'yaml' - content_type = Mime::YAML.to_s - when 'xml' - content_type = Mime::XML.to_s - end - end - - Mime::Type.lookup(content_type) - end + content_type_from_legacy_post_data_format_header || + Mime::Type.lookup(content_type_without_parameters) end # Returns the accepted MIME type for the request @@ -308,13 +290,39 @@ module ActionController def reset_session #:nodoc: end + protected + # The raw content type string. Use when you need parameters such as + # charset or boundary which aren't included in the content_type MIME type. + def content_type_with_parameters + env['CONTENT_TYPE'].to_s + end + + # The raw content type string with its parameters stripped off. + def content_type_without_parameters + @content_type_without_parameters ||= self.class.extract_content_type_without_parameters(content_type_with_parameters) + end + + private + def content_type_from_legacy_post_data_format_header + if x_post_format = @env['HTTP_X_POST_DATA_FORMAT'] + case x_post_format.to_s.downcase + when 'yaml'; Mime::YAML + when 'xml'; Mime::XML + end + end + end + class << self - def parse_formatted_request_parameters(body, content_type, content_length, env = {}) + 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 return {} if content_length.zero? - content_type, boundary = extract_multipart_boundary(content_type.to_s) + content_type, boundary = extract_multipart_boundary(content_type_with_parameters.to_s) return {} if content_type.blank? mime_type = Mime::Type.lookup(content_type) @@ -343,7 +351,7 @@ module ActionController rescue Exception => e # YAML, XML or Ruby code block errors raise { "body" => body, - "content_type" => content_type, + "content_type" => content_type_with_parameters, "content_length" => content_length, "exception" => "#{e.message} (#{e.class})", "backtrace" => e.backtrace } @@ -444,11 +452,11 @@ module ActionController MULTIPART_BOUNDARY = %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n - def extract_multipart_boundary(content_type) - if content_type =~ MULTIPART_BOUNDARY + def extract_multipart_boundary(content_type_with_parameters) + if content_type_with_parameters =~ MULTIPART_BOUNDARY ['multipart/form-data', $1.dup] else - content_type + extract_content_type_without_parameters(content_type_with_parameters) end end diff --git a/actionpack/test/controller/cgi_test.rb b/actionpack/test/controller/cgi_test.rb index 1592795010..4c3fbc37c5 100755 --- a/actionpack/test/controller/cgi_test.rb +++ b/actionpack/test/controller/cgi_test.rb @@ -1,7 +1,7 @@ require File.dirname(__FILE__) + '/../abstract_unit' require 'action_controller/cgi_process' -class CgiRequestTest < Test::Unit::TestCase +class BaseCgiTest < Test::Unit::TestCase def setup @request_hash = {"HTTP_MAX_FORWARDS"=>"10", "SERVER_NAME"=>"glu.ttono.us:8007", "FCGI_ROLE"=>"RESPONDER", "HTTP_X_FORWARDED_HOST"=>"glu.ttono.us", "HTTP_ACCEPT_ENCODING"=>"gzip, deflate", "HTTP_USER_AGENT"=>"Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/312.5.1 (KHTML, like Gecko) Safari/312.3.1", "PATH_INFO"=>"", "HTTP_ACCEPT_LANGUAGE"=>"en", "HTTP_HOST"=>"glu.ttono.us:8007", "SERVER_PROTOCOL"=>"HTTP/1.1", "REDIRECT_URI"=>"/dispatch.fcgi", "SCRIPT_NAME"=>"/dispatch.fcgi", "SERVER_ADDR"=>"207.7.108.53", "REMOTE_ADDR"=>"207.7.108.53", "SERVER_SOFTWARE"=>"lighttpd/1.4.5", "HTTP_COOKIE"=>"_session_id=c84ace84796670c052c6ceb2451fb0f2; is_admin=yes", "HTTP_X_FORWARDED_SERVER"=>"glu.ttono.us", "REQUEST_URI"=>"/admin", "DOCUMENT_ROOT"=>"/home/kevinc/sites/typo/public", "SERVER_PORT"=>"8007", "QUERY_STRING"=>"", "REMOTE_PORT"=>"63137", "GATEWAY_INTERFACE"=>"CGI/1.1", "HTTP_X_FORWARDED_FOR"=>"65.88.180.234", "HTTP_ACCEPT"=>"*/*", "SCRIPT_FILENAME"=>"/home/kevinc/sites/typo/public/dispatch.fcgi", "REDIRECT_STATUS"=>"200", "REQUEST_METHOD"=>"GET"} # cookie as returned by some Nokia phone browsers (no space after semicolon separator) @@ -10,6 +10,11 @@ class CgiRequestTest < Test::Unit::TestCase @request = ActionController::CgiRequest.new(@fake_cgi) end + def default_test; end +end + + +class CgiRequestTest < BaseCgiTest def test_proxy_request assert_equal 'glu.ttono.us', @request.host_with_port end @@ -52,3 +57,14 @@ class CgiRequestTest < Test::Unit::TestCase assert_equal ["yes"], alt_cookies["is_admin"] end end + + +class CgiRequestParamsParsingTest < BaseCgiTest + def test_doesnt_break_when_content_type_has_charset + data = 'flamenco=love' + @request.env['CONTENT_LENGTH'] = data.length + @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' + @request.env['RAW_POST_DATA'] = data + assert_equal({"flamenco"=> "love"}, @request.request_parameters) + end +end |