Sync 'rails/rails/master'

This commit is contained in:
Yehuda Katz
2009-01-09 18:58:38 -08:00
7 changed files with 269 additions and 213 deletions

View File

@@ -6,25 +6,17 @@ require 'active_support/memoizable'
require 'action_controller/cgi_ext'
module ActionController
# CgiRequest and TestRequest provide concrete implementations.
class Request
class Request < Rack::Request
extend ActiveSupport::Memoizable
class SessionFixationAttempt < StandardError #:nodoc:
end
# The hash of environment variables for this request,
# such as { 'RAILS_ENV' => 'production' }.
attr_reader :env
def initialize(env)
@env = env
super
@parser = ActionController::RequestParser.new(env)
end
%w[ AUTH_TYPE GATEWAY_INTERFACE PATH_INFO
%w[ AUTH_TYPE GATEWAY_INTERFACE
PATH_TRANSLATED REMOTE_HOST
REMOTE_IDENT REMOTE_USER SCRIPT_NAME
REMOTE_IDENT REMOTE_USER REMOTE_ADDR
SERVER_NAME SERVER_PROTOCOL
HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
@@ -45,8 +37,7 @@ module ActionController
# The true HTTP request \method as a lowercase symbol, such as <tt>:get</tt>.
# UnknownHttpMethod is raised for invalid methods not listed in ACCEPTED_HTTP_METHODS.
def request_method
method = @env['REQUEST_METHOD']
HTTP_METHOD_LOOKUP[method] || raise(UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence}")
end
memoize :request_method
@@ -93,7 +84,7 @@ module ActionController
# Returns the content length of the request as an integer.
def content_length
@env["action_controller.request.content_length"] ||= @env['CONTENT_LENGTH'].to_i
super.to_i
end
# The MIME type of the HTTP request, such as Mime::XML.
@@ -405,6 +396,7 @@ EOM
def parameters
@parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
end
alias_method :params, :parameters
def path_parameters=(parameters) #:nodoc:
@env["rack.routing_args"] = parameters
@@ -430,31 +422,22 @@ EOM
@parser.body
end
def remote_addr
@env['REMOTE_ADDR']
end
def referrer
@env['HTTP_REFERER']
end
alias referer referrer
def query_parameters
# Override Rack's GET method to support nested query strings
def GET
@parser.query_parameters
end
alias_method :query_parameters, :GET
def request_parameters
# Override Rack's POST method to support nested query strings
def POST
@parser.request_parameters
end
alias_method :request_parameters, :POST
def body_stream #:nodoc:
@env['rack.input']
end
def cookies
Rack::Request.new(@env).cookies
end
def session
@env['rack.session'] ||= {}
end

View File

@@ -91,7 +91,7 @@ module ActionController
end
def content_length
@env["action_controller.request.content_length"] ||= @env['CONTENT_LENGTH'].to_i
@env['CONTENT_LENGTH'].to_i
end
# The raw content type string. Use when you need parameters such as

View File

@@ -0,0 +1,120 @@
require 'abstract_unit'
class QueryStringParsingTest < ActionController::IntegrationTest
class TestController < ActionController::Base
class << self
attr_accessor :last_query_parameters
end
def parse
self.class.last_query_parameters = request.query_parameters
head :ok
end
end
def teardown
TestController.last_query_parameters = nil
end
test "query string" do
assert_parses(
{"action" => "create_customer", "full_name" => "David Heinemeier Hansson", "customerId" => "1"},
"action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1"
)
end
test "deep query string" do
assert_parses(
{'x' => {'y' => {'z' => '10'}}},
"x[y][z]=10"
)
end
test "deep query string with array" do
assert_parses({'x' => {'y' => {'z' => ['10']}}}, 'x[y][z][]=10')
assert_parses({'x' => {'y' => {'z' => ['10', '5']}}}, 'x[y][z][]=10&x[y][z][]=5')
end
test "deep query string with array of hash" do
assert_parses({'x' => {'y' => [{'z' => '10'}]}}, 'x[y][][z]=10')
assert_parses({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, 'x[y][][z]=10&x[y][][w]=10')
assert_parses({'x' => {'y' => [{'z' => '10', 'v' => {'w' => '10'}}]}}, 'x[y][][z]=10&x[y][][v][w]=10')
end
test "deep query string with array of hashes with one pair" do
assert_parses({'x' => {'y' => [{'z' => '10'}, {'z' => '20'}]}}, 'x[y][][z]=10&x[y][][z]=20')
end
test "deep query string with array of hashes with multiple pairs" do
assert_parses(
{'x' => {'y' => [{'z' => '10', 'w' => 'a'}, {'z' => '20', 'w' => 'b'}]}},
'x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b'
)
end
test "query string with nil" do
assert_parses(
{ "action" => "create_customer", "full_name" => ''},
"action=create_customer&full_name="
)
end
test "query string with array" do
assert_parses(
{ "action" => "create_customer", "selected" => ["1", "2", "3"]},
"action=create_customer&selected[]=1&selected[]=2&selected[]=3"
)
end
test "query string with amps" do
assert_parses(
{ "action" => "create_customer", "name" => "Don't & Does"},
"action=create_customer&name=Don%27t+%26+Does"
)
end
test "query string with many equal" do
assert_parses(
{ "action" => "create_customer", "full_name" => "abc=def=ghi"},
"action=create_customer&full_name=abc=def=ghi"
)
end
test "query string without equal" do
assert_parses({ "action" => nil }, "action")
end
test "query string with empty key" do
assert_parses(
{ "action" => "create_customer", "full_name" => "David Heinemeier Hansson" },
"action=create_customer&full_name=David%20Heinemeier%20Hansson&=Save"
)
end
test "query string with many ampersands" do
assert_parses(
{ "action" => "create_customer", "full_name" => "David Heinemeier Hansson"},
"&action=create_customer&&&full_name=David%20Heinemeier%20Hansson"
)
end
test "unbalanced query string with array" do
assert_parses(
{'location' => ["1", "2"], 'age_group' => ["2"]},
"location[]=1&location[]=2&age_group[]=2"
)
end
private
def assert_parses(expected, actual)
with_routing do |set|
set.draw do |map|
map.connect ':action', :controller => "query_string_parsing_test/test"
end
get "/parse", actual
assert_response :ok
assert_equal(expected, TestController.last_query_parameters)
end
end
end

View File

@@ -0,0 +1,45 @@
require 'abstract_unit'
class JsonParamsParsingTest < ActionController::IntegrationTest
class TestController < ActionController::Base
class << self
attr_accessor :last_request_parameters
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 json params for application json" do
assert_parses(
{"person" => {"name" => "David"}},
"{\"person\": {\"name\": \"David\"}}", { 'CONTENT_TYPE' => 'application/json' }
)
end
test "parses json params for application jsonrequest" do
assert_parses(
{"person" => {"name" => "David"}},
"{\"person\": {\"name\": \"David\"}}", { 'CONTENT_TYPE' => 'application/jsonrequest' }
)
end
private
def assert_parses(expected, actual, headers = {})
with_routing do |set|
set.draw do |map|
map.connect ':action', :controller => "json_params_parsing_test/test"
end
post "/parse", actual, headers
assert_response :ok
assert_equal(expected, TestController.last_request_parameters)
end
end
end

View File

@@ -0,0 +1,88 @@
require 'abstract_unit'
class XmlParamsParsingTest < ActionController::IntegrationTest
class TestController < ActionController::Base
class << self
attr_accessor :last_request_parameters
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 hash params" do
with_test_routing do
xml = "<person><name>David</name></person>"
post "/parse", xml, default_headers
assert_response :ok
assert_equal({"person" => {"name" => "David"}}, TestController.last_request_parameters)
end
end
test "parses single file" do
with_test_routing do
xml = "<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></person>"
post "/parse", xml, default_headers
assert_response :ok
person = TestController.last_request_parameters
assert_equal "image/jpg", person['person']['avatar'].content_type
assert_equal "me.jpg", person['person']['avatar'].original_filename
assert_equal "ABC", person['person']['avatar'].read
end
end
test "parses multiple files" do
xml = <<-end_body
<person>
<name>David</name>
<avatars>
<avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar>
<avatar type='file' name='you.gif' content_type='image/gif'>#{ActiveSupport::Base64.encode64('DEF')}</avatar>
</avatars>
</person>
end_body
with_test_routing do
post "/parse", xml, default_headers
assert_response :ok
end
person = TestController.last_request_parameters
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
assert_equal "image/gif", person['person']['avatars']['avatar'].last.content_type
assert_equal "you.gif", person['person']['avatars']['avatar'].last.original_filename
assert_equal "DEF", person['person']['avatars']['avatar'].last.read
end
private
def with_test_routing
with_routing do |set|
set.draw do |map|
map.connect ':action', :controller => "xml_params_parsing_test/test"
end
yield
end
end
def default_headers
{'CONTENT_TYPE' => 'application/xml'}
end
end
class LegacyXmlParamsParsingTest < XmlParamsParsingTest
private
def default_headers
{'HTTP_X_POST_DATA_FORMAT' => 'xml'}
end
end

View File

@@ -407,114 +407,10 @@ class RequestTest < ActiveSupport::TestCase
end
class UrlEncodedRequestParameterParsingTest < ActiveSupport::TestCase
def setup
@query_string = "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1"
@query_string_with_empty = "action=create_customer&full_name="
@query_string_with_array = "action=create_customer&selected[]=1&selected[]=2&selected[]=3"
@query_string_with_amps = "action=create_customer&name=Don%27t+%26+Does"
@query_string_with_multiple_of_same_name =
"action=update_order&full_name=Lau%20Taarnskov&products=4&products=2&products=3"
@query_string_with_many_equal = "action=create_customer&full_name=abc=def=ghi"
@query_string_without_equal = "action"
@query_string_with_many_ampersands =
"&action=create_customer&&&full_name=David%20Heinemeier%20Hansson"
@query_string_with_empty_key = "action=create_customer&full_name=David%20Heinemeier%20Hansson&=Save"
end
def test_query_string
assert_equal(
{ "action" => "create_customer", "full_name" => "David Heinemeier Hansson", "customerId" => "1"},
ActionController::RequestParser.parse_query_parameters(@query_string)
)
end
def test_deep_query_string
expected = {'x' => {'y' => {'z' => '10'}}}
assert_equal(expected, ActionController::RequestParser.parse_query_parameters('x[y][z]=10'))
end
def test_deep_query_string_with_array
assert_equal({'x' => {'y' => {'z' => ['10']}}}, ActionController::RequestParser.parse_query_parameters('x[y][z][]=10'))
assert_equal({'x' => {'y' => {'z' => ['10', '5']}}}, ActionController::RequestParser.parse_query_parameters('x[y][z][]=10&x[y][z][]=5'))
end
def test_deep_query_string_with_array_of_hash
assert_equal({'x' => {'y' => [{'z' => '10'}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10'))
assert_equal({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][w]=10'))
assert_equal({'x' => {'y' => [{'z' => '10', 'v' => {'w' => '10'}}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][v][w]=10'))
end
def test_deep_query_string_with_array_of_hashes_with_one_pair
assert_equal({'x' => {'y' => [{'z' => '10'}, {'z' => '20'}]}}, ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][z]=20'))
assert_equal("10", ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][z]=20')["x"]["y"].first["z"])
assert_equal("10", ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][z]=20').with_indifferent_access[:x][:y].first[:z])
end
def test_deep_query_string_with_array_of_hashes_with_multiple_pairs
assert_equal(
{'x' => {'y' => [{'z' => '10', 'w' => 'a'}, {'z' => '20', 'w' => 'b'}]}},
ActionController::RequestParser.parse_query_parameters('x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b')
)
end
def test_query_string_with_nil
assert_equal(
{ "action" => "create_customer", "full_name" => ''},
ActionController::RequestParser.parse_query_parameters(@query_string_with_empty)
)
end
def test_query_string_with_array
assert_equal(
{ "action" => "create_customer", "selected" => ["1", "2", "3"]},
ActionController::RequestParser.parse_query_parameters(@query_string_with_array)
)
end
def test_query_string_with_amps
assert_equal(
{ "action" => "create_customer", "name" => "Don't & Does"},
ActionController::RequestParser.parse_query_parameters(@query_string_with_amps)
)
end
def test_query_string_with_many_equal
assert_equal(
{ "action" => "create_customer", "full_name" => "abc=def=ghi"},
ActionController::RequestParser.parse_query_parameters(@query_string_with_many_equal)
)
end
def test_query_string_without_equal
assert_equal(
{ "action" => nil },
ActionController::RequestParser.parse_query_parameters(@query_string_without_equal)
)
end
def test_query_string_with_empty_key
assert_equal(
{ "action" => "create_customer", "full_name" => "David Heinemeier Hansson" },
ActionController::RequestParser.parse_query_parameters(@query_string_with_empty_key)
)
end
def test_query_string_with_many_ampersands
assert_equal(
{ "action" => "create_customer", "full_name" => "David Heinemeier Hansson"},
ActionController::RequestParser.parse_query_parameters(@query_string_with_many_ampersands)
)
end
def test_unbalanced_query_string_with_array
assert_equal(
{'location' => ["1", "2"], 'age_group' => ["2"]},
ActionController::RequestParser.parse_query_parameters("location[]=1&location[]=2&age_group[]=2")
)
assert_equal(
{'location' => ["1", "2"], 'age_group' => ["2"]},
ActionController::RequestParser.parse_request_parameters({'location[]' => ["1", "2"],
'age_group[]' => ["2"]})
ActionController::RequestParser.parse_request_parameters({'location[]' => ["1", "2"], 'age_group[]' => ["2"]})
)
end
@@ -814,79 +710,3 @@ class MultipartRequestParameterParsingTest < ActiveSupport::TestCase
end
end
end
class XmlParamsParsingTest < ActiveSupport::TestCase
def test_hash_params
person = parse_body("<person><name>David</name></person>")[:person]
assert_kind_of Hash, person
assert_equal 'David', person['name']
end
def test_single_file
person = parse_body("<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></person>")
assert_equal "image/jpg", person['person']['avatar'].content_type
assert_equal "me.jpg", person['person']['avatar'].original_filename
assert_equal "ABC", person['person']['avatar'].read
end
def test_multiple_files
person = parse_body(<<-end_body)
<person>
<name>David</name>
<avatars>
<avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar>
<avatar type='file' name='you.gif' content_type='image/gif'>#{ActiveSupport::Base64.encode64('DEF')}</avatar>
</avatars>
</person>
end_body
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
assert_equal "image/gif", person['person']['avatars']['avatar'].last.content_type
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 = { 'rack.input' => StringIO.new(body),
'CONTENT_TYPE' => 'application/xml',
'CONTENT_LENGTH' => body.size.to_s }
ActionController::Request.new(env).request_parameters
end
end
class LegacyXmlParamsParsingTest < XmlParamsParsingTest
private
def parse_body(body)
env = { 'rack.input' => StringIO.new(body),
'HTTP_X_POST_DATA_FORMAT' => 'xml',
'CONTENT_LENGTH' => body.size.to_s }
ActionController::Request.new(env).request_parameters
end
end
class JsonParamsParsingTest < ActiveSupport::TestCase
def test_hash_params_for_application_json
person = parse_body({:person => {:name => "David"}}.to_json,'application/json')[:person]
assert_kind_of Hash, person
assert_equal 'David', person['name']
end
def test_hash_params_for_application_jsonrequest
person = parse_body({:person => {:name => "David"}}.to_json,'application/jsonrequest')[:person]
assert_kind_of Hash, person
assert_equal 'David', person['name']
end
private
def parse_body(body,content_type)
env = { 'rack.input' => StringIO.new(body),
'CONTENT_TYPE' => content_type,
'CONTENT_LENGTH' => body.size.to_s }
ActionController::Request.new(env).request_parameters
end
end

View File

@@ -12,7 +12,7 @@ module ActiveSupport
if benchmark = ARGV.include?('--benchmark') # HAX for rake test
{ :benchmark => true,
:runs => 4,
:metrics => [:process_time, :memory, :objects, :gc_runs, :gc_time],
:metrics => [:wall_time, :memory, :objects, :gc_runs, :gc_time],
:output => 'tmp/performance' }
else
{ :benchmark => false,