Changeset 4388
- Timestamp:
- 06/01/06 00:01:48 (2 years ago)
- Files:
-
- trunk/actionpack/CHANGELOG (modified) (1 diff)
- trunk/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb (modified) (6 diffs)
- trunk/actionpack/test/controller/cgi_test.rb (modified) (2 diffs)
- trunk/actionpack/test/controller/raw_post_test.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/actionpack/CHANGELOG
r4384 r4388 1 1 *SVN* 2 3 * Cope with missing content type and length headers. Parse parameters from multipart and urlencoded request bodies only. [Jeremy Kemper] 4 5 * Accept multipart PUT parameters. #5235 [guy.naor@famundo.com] 2 6 3 7 * Added interrogation of params[:format] to determine Accept type. If :format is specified and matches a declared extension, like "rss" or "xml", that mime type will be put in front of the accept handler. This means you can link to the same action from different extensions and use that fact to determine output [DHH]. Example: trunk/actionpack/lib/action_controller/cgi_ext/raw_post_data_fix.rb
r3137 r4388 1 1 class CGI #:nodoc: 2 # Add @request.env['RAW_POST_DATA'] for the vegans.3 2 module QueryExtension 4 3 # Initialize the data from the query. … … 6 5 # Handles multipart forms (in particular, forms that involve file uploads). 7 6 # Reads query parameters in the @params field, and cookies into @cookies. 8 def initialize_query ()7 def initialize_query 9 8 @cookies = CGI::Cookie::parse(env_table['HTTP_COOKIE'] || env_table['COOKIE']) 10 9 11 # fix some strange request environments10 # Fix some strange request environments. 12 11 if method = env_table['REQUEST_METHOD'] 13 12 method = method.to_s.downcase.intern … … 16 15 end 17 16 18 if method == :post && (boundary = multipart_form_boundary) 19 @multipart = true 20 @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH'])) 21 else 22 @multipart = false 23 @params = CGI::parse(read_query_params(method) || "") 17 # POST assumes missing Content-Type is application/x-www-form-urlencoded. 18 content_type = env_table['CONTENT_TYPE'] 19 if content_type.blank? && method == :post 20 content_type = 'application/x-www-form-urlencoded' 24 21 end 22 23 # Force content length to zero if missing. 24 content_length = env_table['CONTENT_LENGTH'].to_i 25 26 # Set multipart to false by default. 27 @multipart = false 28 29 # POST and PUT may have params in entity body. If content type is 30 # missing for POST, assume urlencoded. If content type is missing 31 # for PUT, don't assume anything and don't parse the parameters: 32 # it's likely binary data. 33 # 34 # The other HTTP methods have their params in the query string. 35 if method == :post || method == :put 36 if boundary = extract_multipart_form_boundary(content_type) 37 @multipart = true 38 @params = read_multipart(boundary, content_length) 39 elsif content_type.downcase != 'application/x-www-form-urlencoded' 40 read_params(method, content_length) 41 @params = {} 42 end 43 end 44 45 @params ||= CGI.parse(read_params(method, content_length)) 25 46 end 26 47 … … 30 51 end 31 52 32 def multipart_form_boundary33 MULTIPART_FORM_BOUNDARY_RE.match( env_table['CONTENT_TYPE']).to_a.pop53 def extract_multipart_form_boundary(content_type) 54 MULTIPART_FORM_BOUNDARY_RE.match(content_type).to_a.pop 34 55 end 35 56 36 57 if defined? MOD_RUBY 37 def read_ params_from_query58 def read_query 38 59 Apache::request.args || '' 39 60 end 40 61 else 41 def read_ params_from_query62 def read_query 42 63 # fixes CGI querystring parsing for lighttpd 43 64 env_qs = env_table['QUERY_STRING'] … … 50 71 end 51 72 52 def read_ params_from_post73 def read_body(content_length) 53 74 stdinput.binmode if stdinput.respond_to?(:binmode) 54 content = stdinput.read( Integer(env_table['CONTENT_LENGTH'])) || ''55 # fix for Safari Ajax postings that always append \00075 content = stdinput.read(content_length) || '' 76 # Fix for Safari Ajax postings that always append \000 56 77 content.chop! if content[-1] == 0 57 78 content.gsub! /&_=$/, '' … … 59 80 end 60 81 61 def read_ query_params(method)82 def read_params(method, content_length) 62 83 case method 63 84 when :get 64 read_ params_from_query85 read_query 65 86 when :post, :put 66 read_ params_from_post87 read_body(content_length) 67 88 when :cmd 68 89 read_from_cmdline 69 else # when :head, :delete, :options70 read_ params_from_query90 else # :head, :delete, :options, :trace, :connect 91 read_query 71 92 end 72 93 end trunk/actionpack/test/controller/cgi_test.rb
r4343 r4388 236 236 end 237 237 238 238 239 class MultipartCGITest < Test::Unit::TestCase 239 240 FIXTURE_PATH = File.dirname(__FILE__) + '/../fixtures/multipart' … … 316 317 end 317 318 319 # Ensures that PUT works with multipart as well as POST. 320 class PutMultipartCGITest < MultipartCGITest 321 def setup 322 super 323 ENV['REQUEST_METHOD'] = 'PUT' 324 end 325 end 326 318 327 319 328 class CGIRequestTest < Test::Unit::TestCase trunk/actionpack/test/controller/raw_post_test.rb
r468 r4388 6 6 class RawPostDataTest < Test::Unit::TestCase 7 7 def setup 8 ENV.delete('RAW_POST_DATA') 9 @request_body = 'a=1' 10 end 11 12 def test_post_with_urlencoded_body 13 ENV['REQUEST_METHOD'] = 'POST' 14 ENV['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' 15 assert_equal ['1'], cgi_params['a'] 16 assert_has_raw_post_data 17 end 18 19 def test_post_with_empty_content_type_treated_as_urlencoded 8 20 ENV['REQUEST_METHOD'] = 'POST' 9 21 ENV['CONTENT_TYPE'] = '' 10 ENV['CONTENT_LENGTH'] = '0' 22 assert_equal ['1'], cgi_params['a'] 23 assert_has_raw_post_data 11 24 end 12 25 13 def test_raw_post_data 14 process_raw "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1" 26 def test_post_with_unrecognized_content_type_reads_body_but_doesnt_parse_params 27 ENV['REQUEST_METHOD'] = 'POST' 28 ENV['CONTENT_TYPE'] = 'foo/bar' 29 assert cgi_params.empty? 30 assert_has_raw_post_data 31 end 32 33 def test_put_with_urlencoded_body 34 ENV['REQUEST_METHOD'] = 'PUT' 35 ENV['CONTENT_TYPE'] = 'application/x-www-form-urlencoded' 36 assert_equal ['1'], cgi_params['a'] 37 assert_has_raw_post_data 38 end 39 40 def test_put_with_empty_content_type_ignores_body 41 ENV['REQUEST_METHOD'] = 'PUT' 42 ENV['CONTENT_TYPE'] = '' 43 assert cgi_params.empty? 44 assert_has_raw_post_data 45 end 46 47 def test_put_with_unrecognized_content_type_ignores_body 48 ENV['REQUEST_METHOD'] = 'PUT' 49 ENV['CONTENT_TYPE'] = 'foo/bar' 50 assert cgi_params.empty? 51 assert_has_raw_post_data 15 52 end 16 53 17 54 private 18 def process_raw(query_string)19 old_stdin = $stdin20 begin21 $stdin = StringIO.new(query_string.dup)22 ENV['CONTENT_LENGTH'] = $stdin.size.to_s23 CGI.new24 assert_not_nil ENV['RAW_POST_DATA']25 assert ENV['RAW_POST_DATA'].frozen? 26 assert_equal query_string, ENV['RAW_POST_DATA']27 ensure28 $stdin = old_stdin29 end55 def cgi_params 56 old_stdin, $stdin = $stdin, StringIO.new(@request_body.dup) 57 ENV['CONTENT_LENGTH'] = $stdin.size.to_s 58 CGI.new.params 59 ensure 60 $stdin = old_stdin 61 end 62 63 def assert_has_raw_post_data(expected_body = @request_body) 64 assert_not_nil ENV['RAW_POST_DATA'] 65 assert ENV['RAW_POST_DATA'].frozen? 66 assert_equal expected_body, ENV['RAW_POST_DATA'] 30 67 end 31 68 end