mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
66eb3f02cc
Currently Rack raises a TypeError when it encounters a malformed or ambiguous hash like `foo[]=bar&foo[4]=bar`. Rather than pass this through to the application this commit captures the exception and re-raises it using a new ActionController::BadRequest exception. The new ActionController::BadRequest exception returns a 400 error instead of the 500 error that would've been returned by the original TypeError. This allows exception notification libraries to ignore these errors if so desired. Closes #3051
178 lines
4.4 KiB
Ruby
178 lines
4.4 KiB
Ruby
require 'abstract_unit'
|
|
|
|
class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest
|
|
class TestController < ActionController::Base
|
|
class << self
|
|
attr_accessor :last_request_parameters, :last_request_type
|
|
end
|
|
|
|
def parse
|
|
self.class.last_request_parameters = request.request_parameters
|
|
head :ok
|
|
end
|
|
end
|
|
|
|
def teardown
|
|
TestController.last_request_parameters = nil
|
|
end
|
|
|
|
test "parses unbalanced query string with array" do
|
|
assert_parses(
|
|
{'location' => ["1", "2"], 'age_group' => ["2"]},
|
|
"location[]=1&location[]=2&age_group[]=2"
|
|
)
|
|
end
|
|
|
|
test "parses nested hash" do
|
|
query = [
|
|
"note[viewers][viewer][][type]=User",
|
|
"note[viewers][viewer][][id]=1",
|
|
"note[viewers][viewer][][type]=Group",
|
|
"note[viewers][viewer][][id]=2"
|
|
].join("&")
|
|
|
|
expected = { "note" => { "viewers"=>{"viewer"=>[{ "id"=>"1", "type"=>"User"}, {"type"=>"Group", "id"=>"2"} ]} } }
|
|
assert_parses(expected, query)
|
|
end
|
|
|
|
test "parses more complex nesting" do
|
|
query = [
|
|
"customers[boston][first][name]=David",
|
|
"customers[boston][first][url]=http://David",
|
|
"customers[boston][second][name]=Allan",
|
|
"customers[boston][second][url]=http://Allan",
|
|
"something_else=blah",
|
|
"something_nil=",
|
|
"something_empty=",
|
|
"products[first]=Apple Computer",
|
|
"products[second]=Pc",
|
|
"=Save"
|
|
].join("&")
|
|
|
|
expected = {
|
|
"customers" => {
|
|
"boston" => {
|
|
"first" => {
|
|
"name" => "David",
|
|
"url" => "http://David"
|
|
},
|
|
"second" => {
|
|
"name" => "Allan",
|
|
"url" => "http://Allan"
|
|
}
|
|
}
|
|
},
|
|
"something_else" => "blah",
|
|
"something_empty" => "",
|
|
"something_nil" => "",
|
|
"products" => {
|
|
"first" => "Apple Computer",
|
|
"second" => "Pc"
|
|
}
|
|
}
|
|
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "parses params with array" do
|
|
query = "selected[]=1&selected[]=2&selected[]=3"
|
|
expected = { "selected" => [ "1", "2", "3" ] }
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "parses params with nil key" do
|
|
query = "=&test2=value1"
|
|
expected = { "test2" => "value1" }
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "parses params with array prefix and hashes" do
|
|
query = "a[][b][c]=d"
|
|
expected = {"a" => [{"b" => {"c" => "d"}}]}
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "parses params with complex nesting" do
|
|
query = "a[][b][c][][d][]=e"
|
|
expected = {"a" => [{"b" => {"c" => [{"d" => ["e"]}]}}]}
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "parses params with file path" do
|
|
query = [
|
|
"customers[boston][first][name]=David",
|
|
"something_else=blah",
|
|
"logo=#{File.expand_path(__FILE__)}"
|
|
].join("&")
|
|
|
|
expected = {
|
|
"customers" => {
|
|
"boston" => {
|
|
"first" => {
|
|
"name" => "David"
|
|
}
|
|
}
|
|
},
|
|
"something_else" => "blah",
|
|
"logo" => File.expand_path(__FILE__),
|
|
}
|
|
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "parses params with Safari 2 trailing null character" do
|
|
query = "selected[]=1&selected[]=2&selected[]=3\0"
|
|
expected = { "selected" => [ "1", "2", "3" ] }
|
|
assert_parses expected, query
|
|
end
|
|
|
|
test "ambiguous params returns a bad request" do
|
|
with_routing do |set|
|
|
set.draw do
|
|
post ':action', :to => ::UrlEncodedParamsParsingTest::TestController
|
|
end
|
|
|
|
post "/parse", "foo[]=bar&foo[4]=bar"
|
|
assert_response :bad_request
|
|
end
|
|
end
|
|
|
|
private
|
|
def with_test_routing
|
|
with_routing do |set|
|
|
set.draw do
|
|
post ':action', :to => ::UrlEncodedParamsParsingTest::TestController
|
|
end
|
|
yield
|
|
end
|
|
end
|
|
|
|
def assert_parses(expected, actual)
|
|
with_test_routing do
|
|
post "/parse", actual
|
|
assert_response :ok
|
|
assert_equal(expected, TestController.last_request_parameters)
|
|
assert_utf8(TestController.last_request_parameters)
|
|
end
|
|
end
|
|
|
|
def assert_utf8(object)
|
|
correct_encoding = Encoding.default_internal
|
|
|
|
unless object.is_a?(Hash)
|
|
assert_equal correct_encoding, object.encoding, "#{object.inspect} should have been UTF-8"
|
|
return
|
|
end
|
|
|
|
object.each do |k,v|
|
|
case v
|
|
when Hash
|
|
assert_utf8(v)
|
|
when Array
|
|
v.each {|el| assert_utf8(el) }
|
|
else
|
|
assert_utf8(v)
|
|
end
|
|
end
|
|
end
|
|
end
|