From 85750f22c90c914a429116fb908990c5a2c68379 Mon Sep 17 00:00:00 2001 From: Joshua Peek Date: Wed, 28 Jan 2009 22:50:46 -0600 Subject: Move dispatch related tests into test/dispatch --- actionpack/Rakefile | 2 +- actionpack/test/controller/header_test.rb | 14 - .../test/controller/middleware_stack_test.rb | 76 ---- actionpack/test/controller/mime_type_test.rb | 93 ----- actionpack/test/controller/rack_test.rb | 280 -------------- .../controller/request/json_params_parsing_test.rb | 45 --- .../request/multipart_params_parsing_test.rb | 223 ----------- .../request/query_string_parsing_test.rb | 120 ------ .../request/url_encoded_params_parsing_test.rb | 220 ----------- .../controller/request/xml_params_parsing_test.rb | 88 ----- actionpack/test/controller/request_test.rb | 407 -------------------- actionpack/test/dispatch/header_test.rb | 16 + actionpack/test/dispatch/middleware_stack_test.rb | 76 ++++ actionpack/test/dispatch/mime_type_test.rb | 96 +++++ actionpack/test/dispatch/rack_test.rb | 279 ++++++++++++++ .../dispatch/request/json_params_parsing_test.rb | 45 +++ .../request/multipart_params_parsing_test.rb | 223 +++++++++++ .../dispatch/request/query_string_parsing_test.rb | 120 ++++++ .../request/url_encoded_params_parsing_test.rb | 220 +++++++++++ .../dispatch/request/xml_params_parsing_test.rb | 88 +++++ actionpack/test/dispatch/request_test.rb | 409 +++++++++++++++++++++ 21 files changed, 1573 insertions(+), 1567 deletions(-) delete mode 100644 actionpack/test/controller/header_test.rb delete mode 100644 actionpack/test/controller/middleware_stack_test.rb delete mode 100644 actionpack/test/controller/mime_type_test.rb delete mode 100644 actionpack/test/controller/rack_test.rb delete mode 100644 actionpack/test/controller/request/json_params_parsing_test.rb delete mode 100644 actionpack/test/controller/request/multipart_params_parsing_test.rb delete mode 100644 actionpack/test/controller/request/query_string_parsing_test.rb delete mode 100644 actionpack/test/controller/request/url_encoded_params_parsing_test.rb delete mode 100644 actionpack/test/controller/request/xml_params_parsing_test.rb delete mode 100644 actionpack/test/controller/request_test.rb create mode 100644 actionpack/test/dispatch/header_test.rb create mode 100644 actionpack/test/dispatch/middleware_stack_test.rb create mode 100644 actionpack/test/dispatch/mime_type_test.rb create mode 100644 actionpack/test/dispatch/rack_test.rb create mode 100644 actionpack/test/dispatch/request/json_params_parsing_test.rb create mode 100644 actionpack/test/dispatch/request/multipart_params_parsing_test.rb create mode 100644 actionpack/test/dispatch/request/query_string_parsing_test.rb create mode 100644 actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb create mode 100644 actionpack/test/dispatch/request/xml_params_parsing_test.rb create mode 100644 actionpack/test/dispatch/request_test.rb (limited to 'actionpack') diff --git a/actionpack/Rakefile b/actionpack/Rakefile index c389e5a8d6..230a78c069 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -30,7 +30,7 @@ Rake::TestTask.new(:test_action_pack) do |t| # make sure we include the tests in alphabetical order as on some systems # this will not happen automatically and the tests (as a whole) will error - t.test_files = Dir.glob( "test/[cft]*/**/*_test.rb" ).sort + t.test_files = Dir.glob( "test/[cdft]*/**/*_test.rb" ).sort t.verbose = true #t.warning = true diff --git a/actionpack/test/controller/header_test.rb b/actionpack/test/controller/header_test.rb deleted file mode 100644 index 4f13ea00be..0000000000 --- a/actionpack/test/controller/header_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'abstract_unit' - -class HeaderTest < Test::Unit::TestCase - def setup - @headers = ActionDispatch::Http::Headers.new("HTTP_CONTENT_TYPE"=>"text/plain") - end - - def test_content_type_works - assert_equal "text/plain", @headers["Content-Type"] - assert_equal "text/plain", @headers["content-type"] - assert_equal "text/plain", @headers["CONTENT_TYPE"] - assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"] - end -end diff --git a/actionpack/test/controller/middleware_stack_test.rb b/actionpack/test/controller/middleware_stack_test.rb deleted file mode 100644 index e5496c848b..0000000000 --- a/actionpack/test/controller/middleware_stack_test.rb +++ /dev/null @@ -1,76 +0,0 @@ -require 'abstract_unit' - -class MiddlewareStackTest < ActiveSupport::TestCase - class FooMiddleware; end - class BarMiddleware; end - class BazMiddleware; end - - def setup - @stack = ActionDispatch::MiddlewareStack.new - @stack.use FooMiddleware - @stack.use BarMiddleware - end - - test "use should push middleware as class onto the stack" do - assert_difference "@stack.size" do - @stack.use BazMiddleware - end - assert_equal BazMiddleware, @stack.last.klass - end - - test "use should push middleware as a string onto the stack" do - assert_difference "@stack.size" do - @stack.use "MiddlewareStackTest::BazMiddleware" - end - assert_equal BazMiddleware, @stack.last.klass - end - - test "use should push middleware as a symbol onto the stack" do - assert_difference "@stack.size" do - @stack.use :"MiddlewareStackTest::BazMiddleware" - end - assert_equal BazMiddleware, @stack.last.klass - end - - test "use should push middleware class with arguments onto the stack" do - assert_difference "@stack.size" do - @stack.use BazMiddleware, true, :foo => "bar" - end - assert_equal BazMiddleware, @stack.last.klass - assert_equal([true, {:foo => "bar"}], @stack.last.args) - end - - test "insert inserts middleware at the integer index" do - @stack.insert(1, BazMiddleware) - assert_equal BazMiddleware, @stack[1].klass - end - - test "insert_after inserts middleware after the integer index" do - @stack.insert_after(1, BazMiddleware) - assert_equal BazMiddleware, @stack[2].klass - end - - test "insert_before inserts middleware before another middleware class" do - @stack.insert_before(BarMiddleware, BazMiddleware) - assert_equal BazMiddleware, @stack[1].klass - end - - test "insert_after inserts middleware after another middleware class" do - @stack.insert_after(BarMiddleware, BazMiddleware) - assert_equal BazMiddleware, @stack[2].klass - end - - test "swaps one middleware out for another" do - assert_equal FooMiddleware, @stack[0].klass - @stack.swap(FooMiddleware, BazMiddleware) - assert_equal BazMiddleware, @stack[0].klass - end - - test "active returns all only enabled middleware" do - assert_no_difference "@stack.active.size" do - assert_difference "@stack.size" do - @stack.use BazMiddleware, :if => lambda { false } - end - end - end -end diff --git a/actionpack/test/controller/mime_type_test.rb b/actionpack/test/controller/mime_type_test.rb deleted file mode 100644 index c7faa621d9..0000000000 --- a/actionpack/test/controller/mime_type_test.rb +++ /dev/null @@ -1,93 +0,0 @@ -require 'abstract_unit' - -class MimeTypeTest < Test::Unit::TestCase - Mime::Type.register "image/png", :png - Mime::Type.register "application/pdf", :pdf - - def test_parse_single - Mime::LOOKUP.keys.each do |mime_type| - assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type) - end - end - - def test_parse_without_q - accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*" - expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::TEXT, Mime::PDF, Mime::ALL] - assert_equal expect, Mime::Type.parse(accept) - end - - def test_parse_with_q - accept = "text/xml,application/xhtml+xml,text/yaml; q=0.3,application/xml,text/html; q=0.8,image/png,text/plain; q=0.5,application/pdf,*/*; q=0.2" - expect = [Mime::HTML, Mime::XML, Mime::PNG, Mime::PDF, Mime::TEXT, Mime::YAML, Mime::ALL] - assert_equal expect, Mime::Type.parse(accept) - end - - # Accept header send with user HTTP_USER_AGENT: Sunrise/0.42j (Windows XP) - def test_parse_crappy_broken_acceptlines - accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/*,,*/*;q=0.5" - expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL] - assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s } - end - - # Accept header send with user HTTP_USER_AGENT: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1) - def test_parse_crappy_broken_acceptlines2 - accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*" - expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', Mime::ALL ] - assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s } - end - - def test_custom_type - Mime::Type.register("image/gif", :gif) - assert_nothing_raised do - Mime::GIF - assert_equal Mime::GIF, Mime::SET.last - end - ensure - Mime.module_eval { remove_const :GIF if const_defined?(:GIF) } - end - - def test_type_should_be_equal_to_symbol - assert_equal Mime::HTML, 'application/xhtml+xml' - assert_equal Mime::HTML, :html - end - - def test_type_convenience_methods - # Don't test Mime::ALL, since it Mime::ALL#html? == true - types = Mime::SET.to_a.map(&:to_sym).uniq - [:all] - - # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE - types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) } - - types.each do |type| - mime = Mime.const_get(type.to_s.upcase) - assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?" - invalid_types = types - [type] - invalid_types.delete(:html) if Mime::Type.html_types.include?(type) - invalid_types.each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" } - end - end - - def test_mime_all_is_html - assert Mime::ALL.all?, "Mime::ALL is not all?" - assert Mime::ALL.html?, "Mime::ALL is not html?" - end - - def test_verifiable_mime_types - all_types = Mime::SET.to_a.map(&:to_sym) - all_types.uniq! - # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE - all_types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) } - verified, unverified = all_types.partition { |type| Mime::Type.browser_generated_types.include? type } - assert verified.each { |type| assert Mime.const_get(type.to_s.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" } - assert unverified.each { |type| assert !Mime.const_get(type.to_s.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" } - end - - def test_regexp_matcher - assert Mime::JS =~ "text/javascript" - assert Mime::JS =~ "application/javascript" - assert Mime::JS !~ "text/html" - assert !(Mime::JS !~ "text/javascript") - assert !(Mime::JS !~ "application/javascript") - assert Mime::HTML =~ 'application/xhtml+xml' - end -end diff --git a/actionpack/test/controller/rack_test.rb b/actionpack/test/controller/rack_test.rb deleted file mode 100644 index c29902c722..0000000000 --- a/actionpack/test/controller/rack_test.rb +++ /dev/null @@ -1,280 +0,0 @@ -require 'abstract_unit' - -class BaseRackTest < Test::Unit::TestCase - def setup - @env = { - "HTTP_MAX_FORWARDS" => "10", - "SERVER_NAME" => "glu.ttono.us", - "FCGI_ROLE" => "RESPONDER", - "AUTH_TYPE" => "Basic", - "HTTP_X_FORWARDED_HOST" => "glu.ttono.us", - "HTTP_ACCEPT_CHARSET" => "UTF-8", - "HTTP_ACCEPT_ENCODING" => "gzip, deflate", - "HTTP_CACHE_CONTROL" => "no-cache, max-age=0", - "HTTP_PRAGMA" => "no-cache", - "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", - "PATH_INFO" => "/homepage/", - "HTTP_ACCEPT_LANGUAGE" => "en", - "HTTP_NEGOTIATE" => "trans", - "HTTP_HOST" => "glu.ttono.us:8007", - "HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us", - "HTTP_FROM" => "googlebot", - "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", - "REMOTE_HOST" => "google.com", - "REMOTE_IDENT" => "kevin", - "REMOTE_USER" => "kevin", - "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", - "PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/", - "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" - } - @request = ActionDispatch::Request.new(@env) - # some Nokia phone browsers omit the space after the semicolon separator. - # some developers have grown accustomed to using comma in cookie values. - @alt_cookie_fmt_request = ActionDispatch::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"})) - end - - def default_test; end - - private - - def set_content_data(data) - @request.env['REQUEST_METHOD'] = 'POST' - @request.env['CONTENT_LENGTH'] = data.length - @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' - @request.env['rack.input'] = StringIO.new(data) - end -end - -class RackRequestTest < BaseRackTest - def test_proxy_request - assert_equal 'glu.ttono.us', @request.host_with_port(true) - end - - def test_http_host - @env.delete "HTTP_X_FORWARDED_HOST" - @env['HTTP_HOST'] = "rubyonrails.org:8080" - assert_equal "rubyonrails.org", @request.host(true) - assert_equal "rubyonrails.org:8080", @request.host_with_port(true) - - @env['HTTP_X_FORWARDED_HOST'] = "www.firsthost.org, www.secondhost.org" - assert_equal "www.secondhost.org", @request.host(true) - end - - def test_http_host_with_default_port_overrides_server_port - @env.delete "HTTP_X_FORWARDED_HOST" - @env['HTTP_HOST'] = "rubyonrails.org" - assert_equal "rubyonrails.org", @request.host_with_port(true) - end - - def test_host_with_port_defaults_to_server_name_if_no_host_headers - @env.delete "HTTP_X_FORWARDED_HOST" - @env.delete "HTTP_HOST" - assert_equal "glu.ttono.us:8007", @request.host_with_port(true) - end - - def test_host_with_port_falls_back_to_server_addr_if_necessary - @env.delete "HTTP_X_FORWARDED_HOST" - @env.delete "HTTP_HOST" - @env.delete "SERVER_NAME" - assert_equal "207.7.108.53", @request.host(true) - assert_equal 8007, @request.port(true) - assert_equal "207.7.108.53:8007", @request.host_with_port(true) - end - - def test_host_with_port_if_http_standard_port_is_specified - @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:80" - assert_equal "glu.ttono.us", @request.host_with_port(true) - end - - def test_host_with_port_if_https_standard_port_is_specified - @env['HTTP_X_FORWARDED_PROTO'] = "https" - @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:443" - assert_equal "glu.ttono.us", @request.host_with_port(true) - end - - def test_host_if_ipv6_reference - @env.delete "HTTP_X_FORWARDED_HOST" - @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]" - assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host(true) - end - - def test_host_if_ipv6_reference_with_port - @env.delete "HTTP_X_FORWARDED_HOST" - @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]:8008" - assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host(true) - end - - def test_cgi_environment_variables - assert_equal "Basic", @request.auth_type - assert_equal 0, @request.content_length - assert_equal nil, @request.content_type - assert_equal "CGI/1.1", @request.gateway_interface - assert_equal "*/*", @request.accept - assert_equal "UTF-8", @request.accept_charset - assert_equal "gzip, deflate", @request.accept_encoding - assert_equal "en", @request.accept_language - assert_equal "no-cache, max-age=0", @request.cache_control - assert_equal "googlebot", @request.from - assert_equal "glu.ttono.us", @request.host - assert_equal "trans", @request.negotiate - assert_equal "no-cache", @request.pragma - assert_equal "http://www.google.com/search?q=glu.ttono.us", @request.referer - assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", @request.user_agent - assert_equal "/homepage/", @request.path_info - assert_equal "/home/kevinc/sites/typo/public/homepage/", @request.path_translated - assert_equal "", @request.query_string - assert_equal "207.7.108.53", @request.remote_addr - assert_equal "google.com", @request.remote_host - assert_equal "kevin", @request.remote_ident - assert_equal "kevin", @request.remote_user - assert_equal :get, @request.request_method - assert_equal "/dispatch.fcgi", @request.script_name - assert_equal "glu.ttono.us", @request.server_name - assert_equal 8007, @request.server_port - assert_equal "HTTP/1.1", @request.server_protocol - assert_equal "lighttpd", @request.server_software - end - - def test_cookie_syntax_resilience - cookies = @request.cookies - assert_equal "c84ace84796670c052c6ceb2451fb0f2", cookies["_session_id"], cookies.inspect - assert_equal "yes", cookies["is_admin"], cookies.inspect - - alt_cookies = @alt_cookie_fmt_request.cookies - #assert_equal "c84ace847,96670c052c6ceb2451fb0f2", alt_cookies["_session_id"], alt_cookies.inspect - assert_equal "yes", alt_cookies["is_admin"], alt_cookies.inspect - end -end - -class RackRequestParamsParsingTest < BaseRackTest - def test_doesnt_break_when_content_type_has_charset - set_content_data 'flamenco=love' - - assert_equal({"flamenco"=> "love"}, @request.request_parameters) - end - - def test_doesnt_interpret_request_uri_as_query_string_when_missing - @request.env['REQUEST_URI'] = 'foo' - assert_equal({}, @request.query_parameters) - end -end - -class RackRequestContentTypeTest < BaseRackTest - def test_html_content_type_verification - @request.env['CONTENT_TYPE'] = Mime::HTML.to_s - assert @request.content_type.verify_request? - end - - def test_xml_content_type_verification - @request.env['CONTENT_TYPE'] = Mime::XML.to_s - assert !@request.content_type.verify_request? - end -end - -class RackRequestNeedsRewoundTest < BaseRackTest - def test_body_should_be_rewound - data = 'foo' - @env['rack.input'] = StringIO.new(data) - @env['CONTENT_LENGTH'] = data.length - @env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' - - # Read the request body by parsing params. - request = ActionDispatch::Request.new(@env) - request.request_parameters - - # Should have rewound the body. - assert_equal 0, request.body.pos - end -end - -class RackResponseTest < BaseRackTest - def setup - super - @response = ActionDispatch::Response.new - end - - def test_simple_output - @response.body = "Hello, World!" - @response.prepare! - - status, headers, body = @response.to_a - assert_equal 200, status - assert_equal({ - "Content-Type" => "text/html; charset=utf-8", - "Cache-Control" => "private, max-age=0, must-revalidate", - "ETag" => '"65a8e27d8879283831b664bd8b7f0ad4"', - "Set-Cookie" => [], - "Content-Length" => "13" - }, headers) - - parts = [] - body.each { |part| parts << part } - assert_equal ["Hello, World!"], parts - end - - def test_streaming_block - @response.body = Proc.new do |response, output| - 5.times { |n| output.write(n) } - end - @response.prepare! - - status, headers, body = @response.to_a - assert_equal 200, status - assert_equal({ - "Content-Type" => "text/html; charset=utf-8", - "Content-Length" => "", - "Cache-Control" => "no-cache", - "Set-Cookie" => [] - }, headers) - - parts = [] - body.each { |part| parts << part } - assert_equal ["0", "1", "2", "3", "4"], parts - end -end - -class RackResponseHeadersTest < BaseRackTest - def setup - super - @response = ActionDispatch::Response.new - @response.status = "200 OK" - end - - def test_content_type - [204, 304].each do |c| - @response.status = c.to_s - assert !response_headers.has_key?("Content-Type"), "#{c} should not have Content-Type header" - end - - [200, 302, 404, 500].each do |c| - @response.status = c.to_s - assert response_headers.has_key?("Content-Type"), "#{c} did not have Content-Type header" - end - end - - def test_status - assert !response_headers.has_key?('Status') - end - - private - def response_headers - @response.prepare! - @response.to_a[1] - end -end diff --git a/actionpack/test/controller/request/json_params_parsing_test.rb b/actionpack/test/controller/request/json_params_parsing_test.rb deleted file mode 100644 index a3dde72c4e..0000000000 --- a/actionpack/test/controller/request/json_params_parsing_test.rb +++ /dev/null @@ -1,45 +0,0 @@ -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 diff --git a/actionpack/test/controller/request/multipart_params_parsing_test.rb b/actionpack/test/controller/request/multipart_params_parsing_test.rb deleted file mode 100644 index 5b9728cc42..0000000000 --- a/actionpack/test/controller/request/multipart_params_parsing_test.rb +++ /dev/null @@ -1,223 +0,0 @@ -require 'abstract_unit' - -class MultipartParamsParsingTest < 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 - - def read - render :text => "File: #{params[:uploaded_data].read}" - end - end - - FIXTURE_PATH = File.dirname(__FILE__) + '/../../fixtures/multipart' - - def teardown - TestController.last_request_parameters = nil - end - - test "parses single parameter" do - assert_equal({ 'foo' => 'bar' }, parse_multipart('single_parameter')) - end - - test "parses bracketed parameters" do - assert_equal({ 'foo' => { 'baz' => 'bar'}}, parse_multipart('bracketed_param')) - end - - test "parses text file" do - params = parse_multipart('text_file') - assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] - - file = params['file'] - assert_kind_of Tempfile, file - assert_equal 'file.txt', file.original_filename - assert_equal "text/plain", file.content_type - assert_equal 'contents', file.read - end - - test "parses boundary problem file" do - params = parse_multipart('boundary_problem_file') - assert_equal %w(file foo), params.keys.sort - - file = params['file'] - foo = params['foo'] - - assert_kind_of Tempfile, file - - assert_equal 'file.txt', file.original_filename - assert_equal "text/plain", file.content_type - - assert_equal 'bar', foo - end - - test "parses large text file" do - params = parse_multipart('large_text_file') - assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] - - file = params['file'] - - assert_kind_of Tempfile, file - - assert_equal 'file.txt', file.original_filename - assert_equal "text/plain", file.content_type - assert ('a' * 20480) == file.read - end - - test "parses binary file" do - params = parse_multipart('binary_file') - assert_equal %w(file flowers foo), params.keys.sort - assert_equal 'bar', params['foo'] - - file = params['file'] - assert_kind_of Tempfile, file - assert_equal 'file.csv', file.original_filename - assert_nil file.content_type - assert_equal 'contents', file.read - - file = params['flowers'] - assert_kind_of Tempfile, file - assert_equal 'flowers.jpg', file.original_filename - assert_equal "image/jpeg", file.content_type - assert_equal 19512, file.size - end - - test "parses mixed files" do - params = parse_multipart('mixed_files') - assert_equal %w(files foo), params.keys.sort - assert_equal 'bar', params['foo'] - - # Ruby CGI doesn't handle multipart/mixed for us. - files = params['files'] - assert_kind_of String, files - files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) - assert_equal 19756, files.size - end - - test "does not create tempfile if no file has been selected" do - params = parse_multipart('none') - assert_equal %w(files submit-name), params.keys.sort - assert_equal 'Larry', params['submit-name'] - assert_equal nil, params['files'] - end - - test "parses empty upload file" do - params = parse_multipart('empty') - assert_equal %w(files submit-name), params.keys.sort - assert_equal 'Larry', params['submit-name'] - assert params['files'] - assert_equal "", params['files'].read - end - - test "uploads and reads binary file" do - with_test_routing do - fixture = FIXTURE_PATH + "/mona_lisa.jpg" - params = { :uploaded_data => fixture_file_upload(fixture, "image/jpg") } - post '/read', params - expected_length = 'File: '.length + File.size(fixture) - assert_equal expected_length, response.content_length - end - end - - test "uploads and reads file" do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - - # The lint wrapper is used in integration tests - # instead of a normal StringIO class - InputWrapper = Rack::Lint::InputWrapper - - test "parses unwindable stream" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - params = parse_multipart('large_text_file') - assert_equal %w(file foo), params.keys.sort - assert_equal 'bar', params['foo'] - end - - test "uploads and reads file with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - - test "passes through rack middleware and uploads file" do - with_muck_middleware do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - end - - test "passes through rack middleware and uploads file with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - - with_muck_middleware do - with_test_routing do - post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") - assert_equal "File: Hello", response.body - end - end - end - - private - def fixture(name) - File.open(File.join(FIXTURE_PATH, name), 'rb') do |file| - { "rack.input" => file.read, - "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x", - "CONTENT_LENGTH" => file.stat.size.to_s } - end - end - - def parse_multipart(name) - with_test_routing do - headers = fixture(name) - post "/parse", headers.delete("rack.input"), headers - assert_response :ok - TestController.last_request_parameters - end - end - - def with_test_routing - with_routing do |set| - set.draw do |map| - map.connect ':action', :controller => "multipart_params_parsing_test/test" - end - yield - end - end - - class MuckMiddleware - def initialize(app) - @app = app - end - - def call(env) - req = Rack::Request.new(env) - req.params # Parse params - @app.call(env) - end - end - - def with_muck_middleware - original_middleware = ActionController::Dispatcher.middleware - middleware = original_middleware.dup - middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware - ActionController::Dispatcher.middleware = middleware - yield - ActionController::Dispatcher.middleware = original_middleware - end -end diff --git a/actionpack/test/controller/request/query_string_parsing_test.rb b/actionpack/test/controller/request/query_string_parsing_test.rb deleted file mode 100644 index a31e326ddf..0000000000 --- a/actionpack/test/controller/request/query_string_parsing_test.rb +++ /dev/null @@ -1,120 +0,0 @@ -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 diff --git a/actionpack/test/controller/request/url_encoded_params_parsing_test.rb b/actionpack/test/controller/request/url_encoded_params_parsing_test.rb deleted file mode 100644 index 9f0535bbcc..0000000000 --- a/actionpack/test/controller/request/url_encoded_params_parsing_test.rb +++ /dev/null @@ -1,220 +0,0 @@ -require 'abstract_unit' - -class UrlEncodedParamsParsingTest < ActionController::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 non alphanumeric name" do - query = "a/b[c]=d" - expected = { "a/b" => { "c" => "d" }} - assert_parses expected, query - end - - test "parses params with single brackets in the middle" do - query = "a/b[c]d=e" - expected = { "a/b" => {} } - assert_parses expected, query - end - - test "parses params with separated brackets" do - query = "a/b@[c]d[e]=f" - expected = { "a/b@" => { }} - assert_parses expected, query - end - - test "parses params with separated brackets and array" do - query = "a/b@[c]d[e][]=f" - expected = { "a/b@" => { }} - assert_parses expected, query - end - - test "parses params with unmatched brackets and array" do - query = "a/b@[c][d[e][]=f" - expected = { "a/b@" => { "c" => { }}} - 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 "parses params with Prototype's hack around Safari 2 trailing null character" do - query = "selected[]=1&selected[]=2&selected[]=3&_=" - expected = { "selected" => [ "1", "2", "3" ] } - assert_parses expected, query - end - - test "passes through rack middleware and parses params" do - with_muck_middleware do - assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") - end - end - - # The lint wrapper is used in integration tests - # instead of a normal StringIO class - InputWrapper = Rack::Lint::InputWrapper - - test "passes through rack middleware and parses params with unwindable input" do - InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) - with_muck_middleware do - assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") - end - end - - private - class MuckMiddleware - def initialize(app) - @app = app - end - - def call(env) - req = Rack::Request.new(env) - req.params # Parse params - @app.call(env) - end - end - - def with_muck_middleware - original_middleware = ActionController::Dispatcher.middleware - middleware = original_middleware.dup - middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware - ActionController::Dispatcher.middleware = middleware - yield - ActionController::Dispatcher.middleware = original_middleware - end - - def with_test_routing - with_routing do |set| - set.draw do |map| - map.connect ':action', :controller => "url_encoded_params_parsing_test/test" - 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) - end - end -end diff --git a/actionpack/test/controller/request/xml_params_parsing_test.rb b/actionpack/test/controller/request/xml_params_parsing_test.rb deleted file mode 100644 index ee764e726e..0000000000 --- a/actionpack/test/controller/request/xml_params_parsing_test.rb +++ /dev/null @@ -1,88 +0,0 @@ -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 = "David" - 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 = "David#{ActiveSupport::Base64.encode64('ABC')}" - 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 - - David - - #{ActiveSupport::Base64.encode64('ABC')} - #{ActiveSupport::Base64.encode64('DEF')} - - - 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 diff --git a/actionpack/test/controller/request_test.rb b/actionpack/test/controller/request_test.rb deleted file mode 100644 index 7097d08076..0000000000 --- a/actionpack/test/controller/request_test.rb +++ /dev/null @@ -1,407 +0,0 @@ -require 'abstract_unit' - -class RequestTest < ActiveSupport::TestCase - def setup - ActionController::Base.relative_url_root = nil - @request = ActionController::TestRequest.new - end - - def teardown - ActionController::Base.relative_url_root = nil - end - - def test_remote_ip - assert_equal '0.0.0.0', @request.remote_ip - - @request.remote_addr = '1.2.3.4' - assert_equal '1.2.3.4', @request.remote_ip(true) - - @request.remote_addr = '1.2.3.4,3.4.5.6' - assert_equal '1.2.3.4', @request.remote_ip(true) - - @request.env['HTTP_CLIENT_IP'] = '2.3.4.5' - assert_equal '1.2.3.4', @request.remote_ip(true) - - @request.remote_addr = '192.168.0.1' - assert_equal '2.3.4.5', @request.remote_ip(true) - @request.env.delete 'HTTP_CLIENT_IP' - - @request.remote_addr = '1.2.3.4' - @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' - assert_equal '1.2.3.4', @request.remote_ip(true) - - @request.remote_addr = '127.0.0.1' - @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1' - assert_equal 'unknown', @request.remote_ip(true) - - @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4' - assert_equal '3.4.5.6', @request.remote_ip(true) - - @request.env['HTTP_CLIENT_IP'] = '8.8.8.8' - e = assert_raises(ActionController::ActionControllerError) { - @request.remote_ip(true) - } - assert_match /IP spoofing attack/, e.message - assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message - assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message - - # turn IP Spoofing detection off. - # This is useful for sites that are aimed at non-IP clients. The typical - # example is WAP. Since the cellular network is not IP based, it's a - # leap of faith to assume that their proxies are ever going to set the - # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly. - ActionController::Base.ip_spoofing_check = false - assert_equal('8.8.8.8', @request.remote_ip(true)) - ActionController::Base.ip_spoofing_check = true - - @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9' - assert_equal '8.8.8.8', @request.remote_ip(true) - - @request.env.delete 'HTTP_CLIENT_IP' - @request.env.delete 'HTTP_X_FORWARDED_FOR' - end - - def test_domains - @request.host = "www.rubyonrails.org" - assert_equal "rubyonrails.org", @request.domain - - @request.host = "www.rubyonrails.co.uk" - assert_equal "rubyonrails.co.uk", @request.domain(2) - - @request.host = "192.168.1.200" - assert_nil @request.domain - - @request.host = "foo.192.168.1.200" - assert_nil @request.domain - - @request.host = "192.168.1.200.com" - assert_equal "200.com", @request.domain - - @request.host = nil - assert_nil @request.domain - end - - def test_subdomains - @request.host = "www.rubyonrails.org" - assert_equal %w( www ), @request.subdomains - - @request.host = "www.rubyonrails.co.uk" - assert_equal %w( www ), @request.subdomains(2) - - @request.host = "dev.www.rubyonrails.co.uk" - assert_equal %w( dev www ), @request.subdomains(2) - - @request.host = "foobar.foobar.com" - assert_equal %w( foobar ), @request.subdomains - - @request.host = "192.168.1.200" - assert_equal [], @request.subdomains - - @request.host = "foo.192.168.1.200" - assert_equal [], @request.subdomains - - @request.host = "192.168.1.200.com" - assert_equal %w( 192 168 1 ), @request.subdomains - - @request.host = nil - assert_equal [], @request.subdomains - end - - def test_port_string - @request.port = 80 - assert_equal "", @request.port_string - - @request.port = 8080 - assert_equal ":8080", @request.port_string - end - - def test_request_uri - @request.env['SERVER_SOFTWARE'] = 'Apache 42.342.3432' - - @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri?mapped=1" - assert_equal "/path/of/some/uri?mapped=1", @request.request_uri - assert_equal "/path/of/some/uri", @request.path - - @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri" - assert_equal "/path/of/some/uri", @request.request_uri - assert_equal "/path/of/some/uri", @request.path - - @request.set_REQUEST_URI "/path/of/some/uri" - assert_equal "/path/of/some/uri", @request.request_uri - assert_equal "/path/of/some/uri", @request.path - - @request.set_REQUEST_URI "/" - assert_equal "/", @request.request_uri - assert_equal "/", @request.path - - @request.set_REQUEST_URI "/?m=b" - assert_equal "/?m=b", @request.request_uri - assert_equal "/", @request.path - - @request.set_REQUEST_URI "/" - @request.env['SCRIPT_NAME'] = "/dispatch.cgi" - assert_equal "/", @request.request_uri - assert_equal "/", @request.path - - ActionController::Base.relative_url_root = "/hieraki" - @request.set_REQUEST_URI "/hieraki/" - @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi" - assert_equal "/hieraki/", @request.request_uri - assert_equal "/", @request.path - ActionController::Base.relative_url_root = nil - - ActionController::Base.relative_url_root = "/collaboration/hieraki" - @request.set_REQUEST_URI "/collaboration/hieraki/books/edit/2" - @request.env['SCRIPT_NAME'] = "/collaboration/hieraki/dispatch.cgi" - assert_equal "/collaboration/hieraki/books/edit/2", @request.request_uri - assert_equal "/books/edit/2", @request.path - ActionController::Base.relative_url_root = nil - - # The following tests are for when REQUEST_URI is not supplied (as in IIS) - @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1" - @request.env['SCRIPT_NAME'] = nil #"/path/dispatch.rb" - @request.set_REQUEST_URI nil - assert_equal "/path/of/some/uri?mapped=1", @request.request_uri - assert_equal "/path/of/some/uri", @request.path - - ActionController::Base.relative_url_root = '/path' - @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1" - @request.env['SCRIPT_NAME'] = "/path/dispatch.rb" - @request.set_REQUEST_URI nil - assert_equal "/path/of/some/uri?mapped=1", @request.request_uri(true) - assert_equal "/of/some/uri", @request.path(true) - ActionController::Base.relative_url_root = nil - - @request.env['PATH_INFO'] = "/path/of/some/uri" - @request.env['SCRIPT_NAME'] = nil - @request.set_REQUEST_URI nil - assert_equal "/path/of/some/uri", @request.request_uri - assert_equal "/path/of/some/uri", @request.path - - @request.env['PATH_INFO'] = "/" - @request.set_REQUEST_URI nil - assert_equal "/", @request.request_uri - assert_equal "/", @request.path - - @request.env['PATH_INFO'] = "/?m=b" - @request.set_REQUEST_URI nil - assert_equal "/?m=b", @request.request_uri - assert_equal "/", @request.path - - @request.env['PATH_INFO'] = "/" - @request.env['SCRIPT_NAME'] = "/dispatch.cgi" - @request.set_REQUEST_URI nil - assert_equal "/", @request.request_uri - assert_equal "/", @request.path - - ActionController::Base.relative_url_root = '/hieraki' - @request.env['PATH_INFO'] = "/hieraki/" - @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi" - @request.set_REQUEST_URI nil - assert_equal "/hieraki/", @request.request_uri - assert_equal "/", @request.path - ActionController::Base.relative_url_root = nil - - @request.set_REQUEST_URI '/hieraki/dispatch.cgi' - ActionController::Base.relative_url_root = '/hieraki' - assert_equal "/dispatch.cgi", @request.path(true) - ActionController::Base.relative_url_root = nil - - @request.set_REQUEST_URI '/hieraki/dispatch.cgi' - ActionController::Base.relative_url_root = '/foo' - assert_equal "/hieraki/dispatch.cgi", @request.path(true) - ActionController::Base.relative_url_root = nil - - # This test ensures that Rails uses REQUEST_URI over PATH_INFO - ActionController::Base.relative_url_root = nil - @request.env['REQUEST_URI'] = "/some/path" - @request.env['PATH_INFO'] = "/another/path" - @request.env['SCRIPT_NAME'] = "/dispatch.cgi" - assert_equal "/some/path", @request.request_uri(true) - assert_equal "/some/path", @request.path(true) - end - - def test_host_with_default_port - @request.host = "rubyonrails.org" - @request.port = 80 - assert_equal "rubyonrails.org", @request.host_with_port - end - - def test_host_with_non_default_port - @request.host = "rubyonrails.org" - @request.port = 81 - assert_equal "rubyonrails.org:81", @request.host_with_port - end - - def test_server_software - assert_equal nil, @request.server_software(true) - - @request.env['SERVER_SOFTWARE'] = 'Apache3.422' - assert_equal 'apache', @request.server_software(true) - - @request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)' - assert_equal 'lighttpd', @request.server_software(true) - end - - def test_xml_http_request - assert !@request.xml_http_request? - assert !@request.xhr? - - @request.env['HTTP_X_REQUESTED_WITH'] = "DefinitelyNotAjax1.0" - assert !@request.xml_http_request? - assert !@request.xhr? - - @request.env['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest" - assert @request.xml_http_request? - assert @request.xhr? - end - - def test_reports_ssl - assert !@request.ssl? - @request.env['HTTPS'] = 'on' - assert @request.ssl? - end - - def test_reports_ssl_when_proxied_via_lighttpd - assert !@request.ssl? - @request.env['HTTP_X_FORWARDED_PROTO'] = 'https' - assert @request.ssl? - end - - def test_symbolized_request_methods - [:get, :post, :put, :delete].each do |method| - self.request_method = method - assert_equal method, @request.method - end - end - - def test_invalid_http_method_raises_exception - assert_raises(ActionController::UnknownHttpMethod) do - self.request_method = :random_method - end - end - - def test_allow_method_hacking_on_post - [:get, :head, :options, :put, :post, :delete].each do |method| - self.request_method = method - @request.request_method(true) - assert_equal(method == :head ? :get : method, @request.method) - end - end - - def test_invalid_method_hacking_on_post_raises_exception - assert_raises(ActionController::UnknownHttpMethod) do - self.request_method = :_random_method - @request.request_method(true) - end - end - - def test_restrict_method_hacking - @request.instance_eval { @parameters = { :_method => 'put' } } - [:get, :put, :delete].each do |method| - self.request_method = method - assert_equal method, @request.method - end - end - - def test_head_masquerading_as_get - self.request_method = :head - assert_equal :get, @request.method - assert @request.get? - assert @request.head? - end - - def test_xml_format - @request.instance_eval { @parameters = { :format => 'xml' } } - assert_equal Mime::XML, @request.format - end - - def test_xhtml_format - @request.instance_eval { @parameters = { :format => 'xhtml' } } - assert_equal Mime::HTML, @request.format - end - - def test_txt_format - @request.instance_eval { @parameters = { :format => 'txt' } } - assert_equal Mime::TEXT, @request.format - end - - def test_nil_format - ActionController::Base.use_accept_header, old = - false, ActionController::Base.use_accept_header - - @request.instance_eval { @parameters = {} } - @request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" - assert @request.xhr? - assert_equal Mime::JS, @request.format - - ensure - ActionController::Base.use_accept_header = old - end - - def test_content_type - @request.env["CONTENT_TYPE"] = "text/html" - assert_equal Mime::HTML, @request.content_type - end - - def test_format_assignment_should_set_format - @request.instance_eval { self.format = :txt } - assert !@request.format.xml? - @request.instance_eval { self.format = :xml } - assert @request.format.xml? - end - - def test_content_no_type - assert_equal nil, @request.content_type - end - - def test_content_type_xml - @request.env["CONTENT_TYPE"] = "application/xml" - assert_equal Mime::XML, @request.content_type - end - - def test_content_type_with_charset - @request.env["CONTENT_TYPE"] = "application/xml; charset=UTF-8" - assert_equal Mime::XML, @request.content_type - end - - def test_user_agent - assert_not_nil @request.user_agent - end - - def test_parameters - @request.stubs(:request_parameters).returns({ "foo" => 1 }) - @request.stubs(:query_parameters).returns({ "bar" => 2 }) - - assert_equal({"foo" => 1, "bar" => 2}, @request.parameters) - assert_equal({"foo" => 1}, @request.request_parameters) - assert_equal({"bar" => 2}, @request.query_parameters) - end - - protected - def request_method=(method) - @request.env['REQUEST_METHOD'] = method.to_s.upcase - @request.request_method(true) - end -end diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb new file mode 100644 index 0000000000..ec6ba494dc --- /dev/null +++ b/actionpack/test/dispatch/header_test.rb @@ -0,0 +1,16 @@ +require 'abstract_unit' + +class HeaderTest < ActiveSupport::TestCase + def setup + @headers = ActionDispatch::Http::Headers.new( + "HTTP_CONTENT_TYPE" => "text/plain" + ) + end + + test "content type" do + assert_equal "text/plain", @headers["Content-Type"] + assert_equal "text/plain", @headers["content-type"] + assert_equal "text/plain", @headers["CONTENT_TYPE"] + assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"] + end +end diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb new file mode 100644 index 0000000000..e5496c848b --- /dev/null +++ b/actionpack/test/dispatch/middleware_stack_test.rb @@ -0,0 +1,76 @@ +require 'abstract_unit' + +class MiddlewareStackTest < ActiveSupport::TestCase + class FooMiddleware; end + class BarMiddleware; end + class BazMiddleware; end + + def setup + @stack = ActionDispatch::MiddlewareStack.new + @stack.use FooMiddleware + @stack.use BarMiddleware + end + + test "use should push middleware as class onto the stack" do + assert_difference "@stack.size" do + @stack.use BazMiddleware + end + assert_equal BazMiddleware, @stack.last.klass + end + + test "use should push middleware as a string onto the stack" do + assert_difference "@stack.size" do + @stack.use "MiddlewareStackTest::BazMiddleware" + end + assert_equal BazMiddleware, @stack.last.klass + end + + test "use should push middleware as a symbol onto the stack" do + assert_difference "@stack.size" do + @stack.use :"MiddlewareStackTest::BazMiddleware" + end + assert_equal BazMiddleware, @stack.last.klass + end + + test "use should push middleware class with arguments onto the stack" do + assert_difference "@stack.size" do + @stack.use BazMiddleware, true, :foo => "bar" + end + assert_equal BazMiddleware, @stack.last.klass + assert_equal([true, {:foo => "bar"}], @stack.last.args) + end + + test "insert inserts middleware at the integer index" do + @stack.insert(1, BazMiddleware) + assert_equal BazMiddleware, @stack[1].klass + end + + test "insert_after inserts middleware after the integer index" do + @stack.insert_after(1, BazMiddleware) + assert_equal BazMiddleware, @stack[2].klass + end + + test "insert_before inserts middleware before another middleware class" do + @stack.insert_before(BarMiddleware, BazMiddleware) + assert_equal BazMiddleware, @stack[1].klass + end + + test "insert_after inserts middleware after another middleware class" do + @stack.insert_after(BarMiddleware, BazMiddleware) + assert_equal BazMiddleware, @stack[2].klass + end + + test "swaps one middleware out for another" do + assert_equal FooMiddleware, @stack[0].klass + @stack.swap(FooMiddleware, BazMiddleware) + assert_equal BazMiddleware, @stack[0].klass + end + + test "active returns all only enabled middleware" do + assert_no_difference "@stack.active.size" do + assert_difference "@stack.size" do + @stack.use BazMiddleware, :if => lambda { false } + end + end + end +end diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb new file mode 100644 index 0000000000..2fdf4819bb --- /dev/null +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -0,0 +1,96 @@ +require 'abstract_unit' + +class MimeTypeTest < ActiveSupport::TestCase + Mime::Type.register "image/png", :png unless defined? Mime::PNG + Mime::Type.register "application/pdf", :pdf unless defined? Mime::PDF + + test "parse single" do + Mime::LOOKUP.keys.each do |mime_type| + assert_equal [Mime::Type.lookup(mime_type)], Mime::Type.parse(mime_type) + end + end + + test "parse without q" do + accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*" + expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::TEXT, Mime::PDF, Mime::ALL] + assert_equal expect, Mime::Type.parse(accept) + end + + test "parse with q" do + accept = "text/xml,application/xhtml+xml,text/yaml; q=0.3,application/xml,text/html; q=0.8,image/png,text/plain; q=0.5,application/pdf,*/*; q=0.2" + expect = [Mime::HTML, Mime::XML, Mime::PNG, Mime::PDF, Mime::TEXT, Mime::YAML, Mime::ALL] + assert_equal expect, Mime::Type.parse(accept) + end + + # Accept header send with user HTTP_USER_AGENT: Sunrise/0.42j (Windows XP) + test "parse crappy broken acceptlines" do + accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/*,,*/*;q=0.5" + expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL] + assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s } + end + + # Accept header send with user HTTP_USER_AGENT: Mozilla/4.0 + # (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1) + test "parse crappy broken acceptlines2" do + accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, , pronto/1.00.00, sslvpn/1.00.00.00, */*" + expect = ['image/gif', 'image/x-xbitmap', 'image/jpeg','image/pjpeg', 'application/x-shockwave-flash', 'application/vnd.ms-excel', 'application/vnd.ms-powerpoint', 'application/msword', 'pronto/1.00.00', 'sslvpn/1.00.00.00', Mime::ALL ] + assert_equal expect, Mime::Type.parse(accept).collect { |c| c.to_s } + end + + test "custom type" do + begin + Mime::Type.register("image/gif", :gif) + assert_nothing_raised do + Mime::GIF + assert_equal Mime::GIF, Mime::SET.last + end + ensure + Mime.module_eval { remove_const :GIF if const_defined?(:GIF) } + end + end + + test "type should be equal to symbol" do + assert_equal Mime::HTML, 'application/xhtml+xml' + assert_equal Mime::HTML, :html + end + + test "type convenience methods" do + # Don't test Mime::ALL, since it Mime::ALL#html? == true + types = Mime::SET.to_a.map(&:to_sym).uniq - [:all] + + # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE + types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) } + + types.each do |type| + mime = Mime.const_get(type.to_s.upcase) + assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?" + invalid_types = types - [type] + invalid_types.delete(:html) if Mime::Type.html_types.include?(type) + invalid_types.each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" } + end + end + + test "mime all is html" do + assert Mime::ALL.all?, "Mime::ALL is not all?" + assert Mime::ALL.html?, "Mime::ALL is not html?" + end + + test "verifiable mime types" do + all_types = Mime::SET.to_a.map(&:to_sym) + all_types.uniq! + # Remove custom Mime::Type instances set in other tests, like Mime::GIF and Mime::IPHONE + all_types.delete_if { |type| !Mime.const_defined?(type.to_s.upcase) } + verified, unverified = all_types.partition { |type| Mime::Type.browser_generated_types.include? type } + assert verified.each { |type| assert Mime.const_get(type.to_s.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" } + assert unverified.each { |type| assert !Mime.const_get(type.to_s.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" } + end + + test "regexp matcher" do + assert Mime::JS =~ "text/javascript" + assert Mime::JS =~ "application/javascript" + assert Mime::JS !~ "text/html" + assert !(Mime::JS !~ "text/javascript") + assert !(Mime::JS !~ "application/javascript") + assert Mime::HTML =~ 'application/xhtml+xml' + end +end diff --git a/actionpack/test/dispatch/rack_test.rb b/actionpack/test/dispatch/rack_test.rb new file mode 100644 index 0000000000..df465eba91 --- /dev/null +++ b/actionpack/test/dispatch/rack_test.rb @@ -0,0 +1,279 @@ +require 'abstract_unit' + +# TODO: Merge these tests into RequestTest + +class BaseRackTest < ActiveSupport::TestCase + def setup + @env = { + "HTTP_MAX_FORWARDS" => "10", + "SERVER_NAME" => "glu.ttono.us", + "FCGI_ROLE" => "RESPONDER", + "AUTH_TYPE" => "Basic", + "HTTP_X_FORWARDED_HOST" => "glu.ttono.us", + "HTTP_ACCEPT_CHARSET" => "UTF-8", + "HTTP_ACCEPT_ENCODING" => "gzip, deflate", + "HTTP_CACHE_CONTROL" => "no-cache, max-age=0", + "HTTP_PRAGMA" => "no-cache", + "HTTP_USER_AGENT" => "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", + "PATH_INFO" => "/homepage/", + "HTTP_ACCEPT_LANGUAGE" => "en", + "HTTP_NEGOTIATE" => "trans", + "HTTP_HOST" => "glu.ttono.us:8007", + "HTTP_REFERER" => "http://www.google.com/search?q=glu.ttono.us", + "HTTP_FROM" => "googlebot", + "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", + "REMOTE_HOST" => "google.com", + "REMOTE_IDENT" => "kevin", + "REMOTE_USER" => "kevin", + "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", + "PATH_TRANSLATED" => "/home/kevinc/sites/typo/public/homepage/", + "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" + } + @request = ActionDispatch::Request.new(@env) + # some Nokia phone browsers omit the space after the semicolon separator. + # some developers have grown accustomed to using comma in cookie values. + @alt_cookie_fmt_request = ActionDispatch::Request.new(@env.merge({"HTTP_COOKIE"=>"_session_id=c84ace847,96670c052c6ceb2451fb0f2;is_admin=yes"})) + end + + private + def set_content_data(data) + @request.env['REQUEST_METHOD'] = 'POST' + @request.env['CONTENT_LENGTH'] = data.length + @request.env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' + @request.env['rack.input'] = StringIO.new(data) + end +end + +class RackRequestTest < BaseRackTest + test "proxy request" do + assert_equal 'glu.ttono.us', @request.host_with_port(true) + end + + test "http host" do + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "rubyonrails.org:8080" + assert_equal "rubyonrails.org", @request.host(true) + assert_equal "rubyonrails.org:8080", @request.host_with_port(true) + + @env['HTTP_X_FORWARDED_HOST'] = "www.firsthost.org, www.secondhost.org" + assert_equal "www.secondhost.org", @request.host(true) + end + + test "http host with default port overrides server port" do + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "rubyonrails.org" + assert_equal "rubyonrails.org", @request.host_with_port(true) + end + + test "host with port defaults to server name if no host headers" do + @env.delete "HTTP_X_FORWARDED_HOST" + @env.delete "HTTP_HOST" + assert_equal "glu.ttono.us:8007", @request.host_with_port(true) + end + + test "host with port falls back to server addr if necessary" do + @env.delete "HTTP_X_FORWARDED_HOST" + @env.delete "HTTP_HOST" + @env.delete "SERVER_NAME" + assert_equal "207.7.108.53", @request.host(true) + assert_equal 8007, @request.port(true) + assert_equal "207.7.108.53:8007", @request.host_with_port(true) + end + + test "host with port if http standard port is specified" do + @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:80" + assert_equal "glu.ttono.us", @request.host_with_port(true) + end + + test "host with port if https standard port is specified" do + @env['HTTP_X_FORWARDED_PROTO'] = "https" + @env['HTTP_X_FORWARDED_HOST'] = "glu.ttono.us:443" + assert_equal "glu.ttono.us", @request.host_with_port(true) + end + + test "host if ipv6 reference" do + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]" + assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host(true) + end + + test "host if ipv6 reference with port" do + @env.delete "HTTP_X_FORWARDED_HOST" + @env['HTTP_HOST'] = "[2001:1234:5678:9abc:def0::dead:beef]:8008" + assert_equal "[2001:1234:5678:9abc:def0::dead:beef]", @request.host(true) + end + + test "cgi environment variables" do + assert_equal "Basic", @request.auth_type + assert_equal 0, @request.content_length + assert_equal nil, @request.content_type + assert_equal "CGI/1.1", @request.gateway_interface + assert_equal "*/*", @request.accept + assert_equal "UTF-8", @request.accept_charset + assert_equal "gzip, deflate", @request.accept_encoding + assert_equal "en", @request.accept_language + assert_equal "no-cache, max-age=0", @request.cache_control + assert_equal "googlebot", @request.from + assert_equal "glu.ttono.us", @request.host + assert_equal "trans", @request.negotiate + assert_equal "no-cache", @request.pragma + assert_equal "http://www.google.com/search?q=glu.ttono.us", @request.referer + assert_equal "Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en)", @request.user_agent + assert_equal "/homepage/", @request.path_info + assert_equal "/home/kevinc/sites/typo/public/homepage/", @request.path_translated + assert_equal "", @request.query_string + assert_equal "207.7.108.53", @request.remote_addr + assert_equal "google.com", @request.remote_host + assert_equal "kevin", @request.remote_ident + assert_equal "kevin", @request.remote_user + assert_equal :get, @request.request_method + assert_equal "/dispatch.fcgi", @request.script_name + assert_equal "glu.ttono.us", @request.server_name + assert_equal 8007, @request.server_port + assert_equal "HTTP/1.1", @request.server_protocol + assert_equal "lighttpd", @request.server_software + end + + test "cookie syntax resilience" do + cookies = @request.cookies + assert_equal "c84ace84796670c052c6ceb2451fb0f2", cookies["_session_id"], cookies.inspect + assert_equal "yes", cookies["is_admin"], cookies.inspect + + alt_cookies = @alt_cookie_fmt_request.cookies + #assert_equal "c84ace847,96670c052c6ceb2451fb0f2", alt_cookies["_session_id"], alt_cookies.inspect + assert_equal "yes", alt_cookies["is_admin"], alt_cookies.inspect + end +end + +class RackRequestParamsParsingTest < BaseRackTest + test "doesnt break when content type has charset" do + set_content_data 'flamenco=love' + + assert_equal({"flamenco"=> "love"}, @request.request_parameters) + end + + test "doesnt interpret request uri as query string when missing" do + @request.env['REQUEST_URI'] = 'foo' + assert_equal({}, @request.query_parameters) + end +end + +class RackRequestContentTypeTest < BaseRackTest + test "html content type verification" do + @request.env['CONTENT_TYPE'] = Mime::HTML.to_s + assert @request.content_type.verify_request? + end + + test "xml content type verification" do + @request.env['CONTENT_TYPE'] = Mime::XML.to_s + assert !@request.content_type.verify_request? + end +end + +class RackRequestNeedsRewoundTest < BaseRackTest + test "body should be rewound" do + data = 'foo' + @env['rack.input'] = StringIO.new(data) + @env['CONTENT_LENGTH'] = data.length + @env['CONTENT_TYPE'] = 'application/x-www-form-urlencoded; charset=utf-8' + + # Read the request body by parsing params. + request = ActionDispatch::Request.new(@env) + request.request_parameters + + # Should have rewound the body. + assert_equal 0, request.body.pos + end +end + +class RackResponseTest < BaseRackTest + def setup + super + @response = ActionDispatch::Response.new + end + + test "simple output" do + @response.body = "Hello, World!" + @response.prepare! + + status, headers, body = @response.to_a + assert_equal 200, status + assert_equal({ + "Content-Type" => "text/html; charset=utf-8", + "Cache-Control" => "private, max-age=0, must-revalidate", + "ETag" => '"65a8e27d8879283831b664bd8b7f0ad4"', + "Set-Cookie" => [], + "Content-Length" => "13" + }, headers) + + parts = [] + body.each { |part| parts << part } + assert_equal ["Hello, World!"], parts + end + + test "streaming block" do + @response.body = Proc.new do |response, output| + 5.times { |n| output.write(n) } + end + @response.prepare! + + status, headers, body = @response.to_a + assert_equal 200, status + assert_equal({ + "Content-Type" => "text/html; charset=utf-8", + "Content-Length" => "", + "Cache-Control" => "no-cache", + "Set-Cookie" => [] + }, headers) + + parts = [] + body.each { |part| parts << part } + assert_equal ["0", "1", "2", "3", "4"], parts + end +end + +class RackResponseHeadersTest < BaseRackTest + def setup + super + @response = ActionDispatch::Response.new + @response.status = "200 OK" + end + + test "content type" do + [204, 304].each do |c| + @response.status = c.to_s + assert !response_headers.has_key?("Content-Type"), "#{c} should not have Content-Type header" + end + + [200, 302, 404, 500].each do |c| + @response.status = c.to_s + assert response_headers.has_key?("Content-Type"), "#{c} did not have Content-Type header" + end + end + + test "status" do + assert !response_headers.has_key?('Status') + end + + private + def response_headers + @response.prepare! + @response.to_a[1] + end +end diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb new file mode 100644 index 0000000000..a3dde72c4e --- /dev/null +++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb @@ -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 diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb new file mode 100644 index 0000000000..5b9728cc42 --- /dev/null +++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb @@ -0,0 +1,223 @@ +require 'abstract_unit' + +class MultipartParamsParsingTest < 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 + + def read + render :text => "File: #{params[:uploaded_data].read}" + end + end + + FIXTURE_PATH = File.dirname(__FILE__) + '/../../fixtures/multipart' + + def teardown + TestController.last_request_parameters = nil + end + + test "parses single parameter" do + assert_equal({ 'foo' => 'bar' }, parse_multipart('single_parameter')) + end + + test "parses bracketed parameters" do + assert_equal({ 'foo' => { 'baz' => 'bar'}}, parse_multipart('bracketed_param')) + end + + test "parses text file" do + params = parse_multipart('text_file') + assert_equal %w(file foo), params.keys.sort + assert_equal 'bar', params['foo'] + + file = params['file'] + assert_kind_of Tempfile, file + assert_equal 'file.txt', file.original_filename + assert_equal "text/plain", file.content_type + assert_equal 'contents', file.read + end + + test "parses boundary problem file" do + params = parse_multipart('boundary_problem_file') + assert_equal %w(file foo), params.keys.sort + + file = params['file'] + foo = params['foo'] + + assert_kind_of Tempfile, file + + assert_equal 'file.txt', file.original_filename + assert_equal "text/plain", file.content_type + + assert_equal 'bar', foo + end + + test "parses large text file" do + params = parse_multipart('large_text_file') + assert_equal %w(file foo), params.keys.sort + assert_equal 'bar', params['foo'] + + file = params['file'] + + assert_kind_of Tempfile, file + + assert_equal 'file.txt', file.original_filename + assert_equal "text/plain", file.content_type + assert ('a' * 20480) == file.read + end + + test "parses binary file" do + params = parse_multipart('binary_file') + assert_equal %w(file flowers foo), params.keys.sort + assert_equal 'bar', params['foo'] + + file = params['file'] + assert_kind_of Tempfile, file + assert_equal 'file.csv', file.original_filename + assert_nil file.content_type + assert_equal 'contents', file.read + + file = params['flowers'] + assert_kind_of Tempfile, file + assert_equal 'flowers.jpg', file.original_filename + assert_equal "image/jpeg", file.content_type + assert_equal 19512, file.size + end + + test "parses mixed files" do + params = parse_multipart('mixed_files') + assert_equal %w(files foo), params.keys.sort + assert_equal 'bar', params['foo'] + + # Ruby CGI doesn't handle multipart/mixed for us. + files = params['files'] + assert_kind_of String, files + files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding) + assert_equal 19756, files.size + end + + test "does not create tempfile if no file has been selected" do + params = parse_multipart('none') + assert_equal %w(files submit-name), params.keys.sort + assert_equal 'Larry', params['submit-name'] + assert_equal nil, params['files'] + end + + test "parses empty upload file" do + params = parse_multipart('empty') + assert_equal %w(files submit-name), params.keys.sort + assert_equal 'Larry', params['submit-name'] + assert params['files'] + assert_equal "", params['files'].read + end + + test "uploads and reads binary file" do + with_test_routing do + fixture = FIXTURE_PATH + "/mona_lisa.jpg" + params = { :uploaded_data => fixture_file_upload(fixture, "image/jpg") } + post '/read', params + expected_length = 'File: '.length + File.size(fixture) + assert_equal expected_length, response.content_length + end + end + + test "uploads and reads file" do + with_test_routing do + post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") + assert_equal "File: Hello", response.body + end + end + + # The lint wrapper is used in integration tests + # instead of a normal StringIO class + InputWrapper = Rack::Lint::InputWrapper + + test "parses unwindable stream" do + InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) + params = parse_multipart('large_text_file') + assert_equal %w(file foo), params.keys.sort + assert_equal 'bar', params['foo'] + end + + test "uploads and reads file with unwindable input" do + InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) + + with_test_routing do + post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") + assert_equal "File: Hello", response.body + end + end + + test "passes through rack middleware and uploads file" do + with_muck_middleware do + with_test_routing do + post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") + assert_equal "File: Hello", response.body + end + end + end + + test "passes through rack middleware and uploads file with unwindable input" do + InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) + + with_muck_middleware do + with_test_routing do + post '/read', :uploaded_data => fixture_file_upload(FIXTURE_PATH + "/hello.txt", "text/plain") + assert_equal "File: Hello", response.body + end + end + end + + private + def fixture(name) + File.open(File.join(FIXTURE_PATH, name), 'rb') do |file| + { "rack.input" => file.read, + "CONTENT_TYPE" => "multipart/form-data; boundary=AaB03x", + "CONTENT_LENGTH" => file.stat.size.to_s } + end + end + + def parse_multipart(name) + with_test_routing do + headers = fixture(name) + post "/parse", headers.delete("rack.input"), headers + assert_response :ok + TestController.last_request_parameters + end + end + + def with_test_routing + with_routing do |set| + set.draw do |map| + map.connect ':action', :controller => "multipart_params_parsing_test/test" + end + yield + end + end + + class MuckMiddleware + def initialize(app) + @app = app + end + + def call(env) + req = Rack::Request.new(env) + req.params # Parse params + @app.call(env) + end + end + + def with_muck_middleware + original_middleware = ActionController::Dispatcher.middleware + middleware = original_middleware.dup + middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware + ActionController::Dispatcher.middleware = middleware + yield + ActionController::Dispatcher.middleware = original_middleware + end +end diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb new file mode 100644 index 0000000000..a31e326ddf --- /dev/null +++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb @@ -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 diff --git a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb new file mode 100644 index 0000000000..9f0535bbcc --- /dev/null +++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb @@ -0,0 +1,220 @@ +require 'abstract_unit' + +class UrlEncodedParamsParsingTest < ActionController::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 non alphanumeric name" do + query = "a/b[c]=d" + expected = { "a/b" => { "c" => "d" }} + assert_parses expected, query + end + + test "parses params with single brackets in the middle" do + query = "a/b[c]d=e" + expected = { "a/b" => {} } + assert_parses expected, query + end + + test "parses params with separated brackets" do + query = "a/b@[c]d[e]=f" + expected = { "a/b@" => { }} + assert_parses expected, query + end + + test "parses params with separated brackets and array" do + query = "a/b@[c]d[e][]=f" + expected = { "a/b@" => { }} + assert_parses expected, query + end + + test "parses params with unmatched brackets and array" do + query = "a/b@[c][d[e][]=f" + expected = { "a/b@" => { "c" => { }}} + 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 "parses params with Prototype's hack around Safari 2 trailing null character" do + query = "selected[]=1&selected[]=2&selected[]=3&_=" + expected = { "selected" => [ "1", "2", "3" ] } + assert_parses expected, query + end + + test "passes through rack middleware and parses params" do + with_muck_middleware do + assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") + end + end + + # The lint wrapper is used in integration tests + # instead of a normal StringIO class + InputWrapper = Rack::Lint::InputWrapper + + test "passes through rack middleware and parses params with unwindable input" do + InputWrapper.any_instance.stubs(:rewind).raises(Errno::ESPIPE) + with_muck_middleware do + assert_parses({ "a" => { "b" => "c" } }, "a[b]=c") + end + end + + private + class MuckMiddleware + def initialize(app) + @app = app + end + + def call(env) + req = Rack::Request.new(env) + req.params # Parse params + @app.call(env) + end + end + + def with_muck_middleware + original_middleware = ActionController::Dispatcher.middleware + middleware = original_middleware.dup + middleware.insert_after ActionDispatch::RewindableInput, MuckMiddleware + ActionController::Dispatcher.middleware = middleware + yield + ActionController::Dispatcher.middleware = original_middleware + end + + def with_test_routing + with_routing do |set| + set.draw do |map| + map.connect ':action', :controller => "url_encoded_params_parsing_test/test" + 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) + end + end +end diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb new file mode 100644 index 0000000000..ee764e726e --- /dev/null +++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb @@ -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 = "David" + 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 = "David#{ActiveSupport::Base64.encode64('ABC')}" + 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 + + David + + #{ActiveSupport::Base64.encode64('ABC')} + #{ActiveSupport::Base64.encode64('DEF')} + + + 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 diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb new file mode 100644 index 0000000000..6262763b81 --- /dev/null +++ b/actionpack/test/dispatch/request_test.rb @@ -0,0 +1,409 @@ +require 'abstract_unit' + +class RequestTest < ActiveSupport::TestCase + def setup + ActionController::Base.relative_url_root = nil + @request = ActionController::TestRequest.new + end + + def teardown + ActionController::Base.relative_url_root = nil + end + + test "remote ip" do + assert_equal '0.0.0.0', @request.remote_ip + + @request.remote_addr = '1.2.3.4' + assert_equal '1.2.3.4', @request.remote_ip(true) + + @request.remote_addr = '1.2.3.4,3.4.5.6' + assert_equal '1.2.3.4', @request.remote_ip(true) + + @request.env['HTTP_CLIENT_IP'] = '2.3.4.5' + assert_equal '1.2.3.4', @request.remote_ip(true) + + @request.remote_addr = '192.168.0.1' + assert_equal '2.3.4.5', @request.remote_ip(true) + @request.env.delete 'HTTP_CLIENT_IP' + + @request.remote_addr = '1.2.3.4' + @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' + assert_equal '1.2.3.4', @request.remote_ip(true) + + @request.remote_addr = '127.0.0.1' + @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1' + assert_equal 'unknown', @request.remote_ip(true) + + @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4' + assert_equal '3.4.5.6', @request.remote_ip(true) + + @request.env['HTTP_CLIENT_IP'] = '8.8.8.8' + e = assert_raises(ActionController::ActionControllerError) { + @request.remote_ip(true) + } + assert_match /IP spoofing attack/, e.message + assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message + assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message + + # turn IP Spoofing detection off. + # This is useful for sites that are aimed at non-IP clients. The typical + # example is WAP. Since the cellular network is not IP based, it's a + # leap of faith to assume that their proxies are ever going to set the + # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly. + ActionController::Base.ip_spoofing_check = false + assert_equal('8.8.8.8', @request.remote_ip(true)) + ActionController::Base.ip_spoofing_check = true + + @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9' + assert_equal '8.8.8.8', @request.remote_ip(true) + + @request.env.delete 'HTTP_CLIENT_IP' + @request.env.delete 'HTTP_X_FORWARDED_FOR' + end + + test "domains" do + @request.host = "www.rubyonrails.org" + assert_equal "rubyonrails.org", @request.domain + + @request.host = "www.rubyonrails.co.uk" + assert_equal "rubyonrails.co.uk", @request.domain(2) + + @request.host = "192.168.1.200" + assert_nil @request.domain + + @request.host = "foo.192.168.1.200" + assert_nil @request.domain + + @request.host = "192.168.1.200.com" + assert_equal "200.com", @request.domain + + @request.host = nil + assert_nil @request.domain + end + + test "subdomains" do + @request.host = "www.rubyonrails.org" + assert_equal %w( www ), @request.subdomains + + @request.host = "www.rubyonrails.co.uk" + assert_equal %w( www ), @request.subdomains(2) + + @request.host = "dev.www.rubyonrails.co.uk" + assert_equal %w( dev www ), @request.subdomains(2) + + @request.host = "foobar.foobar.com" + assert_equal %w( foobar ), @request.subdomains + + @request.host = "192.168.1.200" + assert_equal [], @request.subdomains + + @request.host = "foo.192.168.1.200" + assert_equal [], @request.subdomains + + @request.host = "192.168.1.200.com" + assert_equal %w( 192 168 1 ), @request.subdomains + + @request.host = nil + assert_equal [], @request.subdomains + end + + test "port string" do + @request.port = 80 + assert_equal "", @request.port_string + + @request.port = 8080 + assert_equal ":8080", @request.port_string + end + + test "request uri" do + @request.env['SERVER_SOFTWARE'] = 'Apache 42.342.3432' + + @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri?mapped=1" + assert_equal "/path/of/some/uri?mapped=1", @request.request_uri + assert_equal "/path/of/some/uri", @request.path + + @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri" + assert_equal "/path/of/some/uri", @request.request_uri + assert_equal "/path/of/some/uri", @request.path + + @request.set_REQUEST_URI "/path/of/some/uri" + assert_equal "/path/of/some/uri", @request.request_uri + assert_equal "/path/of/some/uri", @request.path + + @request.set_REQUEST_URI "/" + assert_equal "/", @request.request_uri + assert_equal "/", @request.path + + @request.set_REQUEST_URI "/?m=b" + assert_equal "/?m=b", @request.request_uri + assert_equal "/", @request.path + + @request.set_REQUEST_URI "/" + @request.env['SCRIPT_NAME'] = "/dispatch.cgi" + assert_equal "/", @request.request_uri + assert_equal "/", @request.path + + ActionController::Base.relative_url_root = "/hieraki" + @request.set_REQUEST_URI "/hieraki/" + @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi" + assert_equal "/hieraki/", @request.request_uri + assert_equal "/", @request.path + ActionController::Base.relative_url_root = nil + + ActionController::Base.relative_url_root = "/collaboration/hieraki" + @request.set_REQUEST_URI "/collaboration/hieraki/books/edit/2" + @request.env['SCRIPT_NAME'] = "/collaboration/hieraki/dispatch.cgi" + assert_equal "/collaboration/hieraki/books/edit/2", @request.request_uri + assert_equal "/books/edit/2", @request.path + ActionController::Base.relative_url_root = nil + + # The following tests are for when REQUEST_URI is not supplied (as in IIS) + @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1" + @request.env['SCRIPT_NAME'] = nil #"/path/dispatch.rb" + @request.set_REQUEST_URI nil + assert_equal "/path/of/some/uri?mapped=1", @request.request_uri + assert_equal "/path/of/some/uri", @request.path + + ActionController::Base.relative_url_root = '/path' + @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1" + @request.env['SCRIPT_NAME'] = "/path/dispatch.rb" + @request.set_REQUEST_URI nil + assert_equal "/path/of/some/uri?mapped=1", @request.request_uri(true) + assert_equal "/of/some/uri", @request.path(true) + ActionController::Base.relative_url_root = nil + + @request.env['PATH_INFO'] = "/path/of/some/uri" + @request.env['SCRIPT_NAME'] = nil + @request.set_REQUEST_URI nil + assert_equal "/path/of/some/uri", @request.request_uri + assert_equal "/path/of/some/uri", @request.path + + @request.env['PATH_INFO'] = "/" + @request.set_REQUEST_URI nil + assert_equal "/", @request.request_uri + assert_equal "/", @request.path + + @request.env['PATH_INFO'] = "/?m=b" + @request.set_REQUEST_URI nil + assert_equal "/?m=b", @request.request_uri + assert_equal "/", @request.path + + @request.env['PATH_INFO'] = "/" + @request.env['SCRIPT_NAME'] = "/dispatch.cgi" + @request.set_REQUEST_URI nil + assert_equal "/", @request.request_uri + assert_equal "/", @request.path + + ActionController::Base.relative_url_root = '/hieraki' + @request.env['PATH_INFO'] = "/hieraki/" + @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi" + @request.set_REQUEST_URI nil + assert_equal "/hieraki/", @request.request_uri + assert_equal "/", @request.path + ActionController::Base.relative_url_root = nil + + @request.set_REQUEST_URI '/hieraki/dispatch.cgi' + ActionController::Base.relative_url_root = '/hieraki' + assert_equal "/dispatch.cgi", @request.path(true) + ActionController::Base.relative_url_root = nil + + @request.set_REQUEST_URI '/hieraki/dispatch.cgi' + ActionController::Base.relative_url_root = '/foo' + assert_equal "/hieraki/dispatch.cgi", @request.path(true) + ActionController::Base.relative_url_root = nil + + # This test ensures that Rails uses REQUEST_URI over PATH_INFO + ActionController::Base.relative_url_root = nil + @request.env['REQUEST_URI'] = "/some/path" + @request.env['PATH_INFO'] = "/another/path" + @request.env['SCRIPT_NAME'] = "/dispatch.cgi" + assert_equal "/some/path", @request.request_uri(true) + assert_equal "/some/path", @request.path(true) + end + + test "host with default port" do + @request.host = "rubyonrails.org" + @request.port = 80 + assert_equal "rubyonrails.org", @request.host_with_port + end + + test "host with non default port" do + @request.host = "rubyonrails.org" + @request.port = 81 + assert_equal "rubyonrails.org:81", @request.host_with_port + end + + test "server software" do + assert_equal nil, @request.server_software(true) + + @request.env['SERVER_SOFTWARE'] = 'Apache3.422' + assert_equal 'apache', @request.server_software(true) + + @request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)' + assert_equal 'lighttpd', @request.server_software(true) + end + + test "xml http request" do + assert !@request.xml_http_request? + assert !@request.xhr? + + @request.env['HTTP_X_REQUESTED_WITH'] = "DefinitelyNotAjax1.0" + assert !@request.xml_http_request? + assert !@request.xhr? + + @request.env['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest" + assert @request.xml_http_request? + assert @request.xhr? + end + + test "reports ssl" do + assert !@request.ssl? + @request.env['HTTPS'] = 'on' + assert @request.ssl? + end + + test "reports ssl when proxied via lighttpd" do + assert !@request.ssl? + @request.env['HTTP_X_FORWARDED_PROTO'] = 'https' + assert @request.ssl? + end + + test "symbolized request methods" do + [:get, :post, :put, :delete].each do |method| + self.request_method = method + assert_equal method, @request.method + end + end + + test "invalid http method raises exception" do + assert_raises(ActionController::UnknownHttpMethod) do + self.request_method = :random_method + end + end + + test "allow method hacking on post" do + [:get, :head, :options, :put, :post, :delete].each do |method| + self.request_method = method + @request.request_method(true) + assert_equal(method == :head ? :get : method, @request.method) + end + end + + test "invalid method hacking on post raises exception" do + assert_raises(ActionController::UnknownHttpMethod) do + self.request_method = :_random_method + @request.request_method(true) + end + end + + test "restrict method hacking" do + @request.instance_eval { @parameters = { :_method => 'put' } } + [:get, :put, :delete].each do |method| + self.request_method = method + assert_equal method, @request.method + end + end + + test "head masquerading as get" do + self.request_method = :head + assert_equal :get, @request.method + assert @request.get? + assert @request.head? + end + + test "xml format" do + @request.instance_eval { @parameters = { :format => 'xml' } } + assert_equal Mime::XML, @request.format + end + + test "xhtml format" do + @request.instance_eval { @parameters = { :format => 'xhtml' } } + assert_equal Mime::HTML, @request.format + end + + test "txt format" do + @request.instance_eval { @parameters = { :format => 'txt' } } + assert_equal Mime::TEXT, @request.format + end + + test "nil format" do + begin + ActionController::Base.use_accept_header, old = + false, ActionController::Base.use_accept_header + + @request.instance_eval { @parameters = {} } + @request.env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" + assert @request.xhr? + assert_equal Mime::JS, @request.format + + ensure + ActionController::Base.use_accept_header = old + end + end + + test "content type" do + @request.env["CONTENT_TYPE"] = "text/html" + assert_equal Mime::HTML, @request.content_type + end + + test "format assignment should set format" do + @request.instance_eval { self.format = :txt } + assert !@request.format.xml? + @request.instance_eval { self.format = :xml } + assert @request.format.xml? + end + + test "content no type" do + assert_equal nil, @request.content_type + end + + test "content type xml" do + @request.env["CONTENT_TYPE"] = "application/xml" + assert_equal Mime::XML, @request.content_type + end + + test "content type with charset" do + @request.env["CONTENT_TYPE"] = "application/xml; charset=UTF-8" + assert_equal Mime::XML, @request.content_type + end + + test "user agent" do + assert_not_nil @request.user_agent + end + + test "parameters" do + @request.stubs(:request_parameters).returns({ "foo" => 1 }) + @request.stubs(:query_parameters).returns({ "bar" => 2 }) + + assert_equal({"foo" => 1, "bar" => 2}, @request.parameters) + assert_equal({"foo" => 1}, @request.request_parameters) + assert_equal({"bar" => 2}, @request.query_parameters) + end + + protected + def request_method=(method) + @request.env['REQUEST_METHOD'] = method.to_s.upcase + @request.request_method(true) + end +end -- cgit v1.2.3