aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test/dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/test/dispatch')
-rw-r--r--actionpack/test/dispatch/cookies_test.rb44
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb17
-rw-r--r--actionpack/test/dispatch/header_test.rb5
-rw-r--r--actionpack/test/dispatch/live_response_test.rb83
-rw-r--r--actionpack/test/dispatch/mapper_test.rb25
-rw-r--r--actionpack/test/dispatch/middleware_stack_test.rb9
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb32
-rw-r--r--actionpack/test/dispatch/mount_test.rb14
-rw-r--r--actionpack/test/dispatch/prefix_generation_test.rb55
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request/multipart_params_parsing_test.rb2
-rw-r--r--actionpack/test/dispatch/request/query_string_parsing_test.rb24
-rw-r--r--actionpack/test/dispatch/request/session_test.rb73
-rw-r--r--actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb13
-rw-r--r--actionpack/test/dispatch/request/xml_params_parsing_test.rb4
-rw-r--r--actionpack/test/dispatch/request_id_test.rb4
-rw-r--r--actionpack/test/dispatch/request_test.rb183
-rw-r--r--actionpack/test/dispatch/response_test.rb65
-rw-r--r--actionpack/test/dispatch/routing/concerns_test.rb119
-rw-r--r--actionpack/test/dispatch/routing/inspector_test.rb170
-rw-r--r--actionpack/test/dispatch/routing_assertions_test.rb28
-rw-r--r--actionpack/test/dispatch/routing_test.rb437
-rw-r--r--actionpack/test/dispatch/session/abstract_store_test.rb56
-rw-r--r--actionpack/test/dispatch/session/cache_store_test.rb2
-rw-r--r--actionpack/test/dispatch/session/cookie_store_test.rb22
-rw-r--r--actionpack/test/dispatch/session/mem_cache_store_test.rb15
-rw-r--r--actionpack/test/dispatch/ssl_test.rb157
-rw-r--r--actionpack/test/dispatch/static_test.rb4
-rw-r--r--actionpack/test/dispatch/test_request_test.rb7
-rw-r--r--actionpack/test/dispatch/uploaded_file_test.rb8
-rw-r--r--actionpack/test/dispatch/url_generation_test.rb15
31 files changed, 1513 insertions, 183 deletions
diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb
index 3e48d97e67..347b3b3b5a 100644
--- a/actionpack/test/dispatch/cookies_test.rb
+++ b/actionpack/test/dispatch/cookies_test.rb
@@ -38,6 +38,8 @@ class CookiesTest < ActionController::TestCase
head :ok
end
+ alias delete_cookie logout
+
def delete_cookie_with_path
cookies.delete("user_name", :path => '/beaten')
head :ok
@@ -179,6 +181,18 @@ class CookiesTest < ActionController::TestCase
assert_equal({"user_name" => "david"}, @response.cookies)
end
+ def test_setting_the_same_value_to_cookie
+ request.cookies[:user_name] = 'david'
+ get :authenticate
+ assert response.cookies.empty?
+ end
+
+ def test_setting_the_same_value_to_permanent_cookie
+ request.cookies[:user_name] = 'Jamie'
+ get :set_permanent_cookie
+ assert_equal response.cookies, 'user_name' => 'Jamie'
+ end
+
def test_setting_with_escapable_characters
get :set_with_with_escapable_characters
assert_cookie_header "that+%26+guy=foo+%26+bar+%3D%3E+baz; path=/"
@@ -235,23 +249,33 @@ class CookiesTest < ActionController::TestCase
end
def test_expiring_cookie
+ request.cookies[:user_name] = 'Joe'
get :logout
assert_cookie_header "user_name=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
assert_equal({"user_name" => nil}, @response.cookies)
end
def test_delete_cookie_with_path
+ request.cookies[:user_name] = 'Joe'
get :delete_cookie_with_path
assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"
end
+ def test_delete_unexisting_cookie
+ request.cookies.clear
+ get :delete_cookie
+ assert @response.cookies.empty?
+ end
+
def test_deleted_cookie_predicate
+ cookies[:user_name] = 'Joe'
cookies.delete("user_name")
assert cookies.deleted?("user_name")
assert_equal false, cookies.deleted?("another")
end
def test_deleted_cookie_predicate_with_mismatching_options
+ cookies[:user_name] = 'Joe'
cookies.delete("user_name", :path => "/path")
assert_equal false, cookies.deleted?("user_name", :path => "/different")
end
@@ -284,6 +308,7 @@ class CookiesTest < ActionController::TestCase
end
def test_delete_and_set_cookie
+ request.cookies[:user_name] = 'Joe'
get :delete_and_set_cookie
assert_cookie_header "user_name=david; path=/; expires=Mon, 10-Oct-2005 05:00:00 GMT"
assert_equal({"user_name" => "david"}, @response.cookies)
@@ -387,6 +412,7 @@ class CookiesTest < ActionController::TestCase
end
def test_deleting_cookie_with_all_domain_option
+ request.cookies[:user_name] = 'Joe'
get :delete_cookie_with_domain
assert_response :success
assert_cookie_header "user_name=; domain=.nextangle.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
@@ -413,6 +439,7 @@ class CookiesTest < ActionController::TestCase
end
def test_deleting_cookie_with_all_domain_option_and_tld_length
+ request.cookies[:user_name] = 'Joe'
get :delete_cookie_with_domain_and_tld
assert_response :success
assert_cookie_header "user_name=; domain=.nextangle.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
@@ -441,6 +468,7 @@ class CookiesTest < ActionController::TestCase
def test_deletings_cookie_with_several_preset_domains_using_one_of_these_domains
@request.host = "example2.com"
+ request.cookies[:user_name] = 'Joe'
get :delete_cookie_with_domains
assert_response :success
assert_cookie_header "user_name=; domain=example2.com; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
@@ -448,19 +476,19 @@ class CookiesTest < ActionController::TestCase
def test_deletings_cookie_with_several_preset_domains_using_other_domain
@request.host = "other-domain.com"
+ request.cookies[:user_name] = 'Joe'
get :delete_cookie_with_domains
assert_response :success
assert_cookie_header "user_name=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"
end
-
def test_cookies_hash_is_indifferent_access
- get :symbol_key
- assert_equal "david", cookies[:user_name]
- assert_equal "david", cookies['user_name']
- get :string_key
- assert_equal "dhh", cookies[:user_name]
- assert_equal "dhh", cookies['user_name']
+ get :symbol_key
+ assert_equal "david", cookies[:user_name]
+ assert_equal "david", cookies['user_name']
+ get :string_key
+ assert_equal "dhh", cookies[:user_name]
+ assert_equal "dhh", cookies['user_name']
end
@@ -575,4 +603,4 @@ class CookiesTest < ActionController::TestCase
assert_not_equal expected.split("\n"), header
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 11c292d61a..d236b14e02 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -35,6 +35,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
raise ActionController::InvalidAuthenticityToken
when "/not_found_original_exception"
raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
+ when "/bad_request"
+ raise ActionController::BadRequest
+ when "/missing_keys"
+ raise ActionController::UrlGenerationError, "No route matches"
else
raise "puke!"
end
@@ -88,6 +92,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/method_not_allowed", {}, {'action_dispatch.show_exceptions' => true}
assert_response 405
assert_match(/ActionController::MethodNotAllowed/, body)
+
+ get "/bad_request", {}, {'action_dispatch.show_exceptions' => true}
+ assert_response 400
+ assert_match(/ActionController::BadRequest/, body)
end
test "does not show filtered parameters" do
@@ -107,6 +115,15 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_match(/AbstractController::ActionNotFound/, body)
end
+ test "named urls missing keys raise 500 level error" do
+ @app = DevelopmentApp
+
+ get "/missing_keys", {}, {'action_dispatch.show_exceptions' => true}
+ assert_response 500
+
+ assert_match(/ActionController::UrlGenerationError/, body)
+ end
+
test "show the controller name in the diagnostics template when controller name is present" do
@app = DevelopmentApp
get("/runtime_error", {}, {
diff --git a/actionpack/test/dispatch/header_test.rb b/actionpack/test/dispatch/header_test.rb
index ec6ba494dc..bc7cad8db5 100644
--- a/actionpack/test/dispatch/header_test.rb
+++ b/actionpack/test/dispatch/header_test.rb
@@ -13,4 +13,9 @@ class HeaderTest < ActiveSupport::TestCase
assert_equal "text/plain", @headers["CONTENT_TYPE"]
assert_equal "text/plain", @headers["HTTP_CONTENT_TYPE"]
end
+
+ test "fetch" do
+ assert_equal "text/plain", @headers.fetch("content-type", nil)
+ assert_equal "not found", @headers.fetch('not-found', 'not found')
+ end
end
diff --git a/actionpack/test/dispatch/live_response_test.rb b/actionpack/test/dispatch/live_response_test.rb
new file mode 100644
index 0000000000..e16f23914b
--- /dev/null
+++ b/actionpack/test/dispatch/live_response_test.rb
@@ -0,0 +1,83 @@
+require 'abstract_unit'
+require 'active_support/concurrency/latch'
+
+module ActionController
+ module Live
+ class ResponseTest < ActiveSupport::TestCase
+ def setup
+ @response = Live::Response.new
+ end
+
+ def test_header_merge
+ header = @response.header.merge('Foo' => 'Bar')
+ assert_kind_of(ActionController::Live::Response::Header, header)
+ refute_equal header, @response.header
+ end
+
+ def test_initialize_with_default_headers
+ r = Class.new(Live::Response) do
+ def self.default_headers
+ { 'omg' => 'g' }
+ end
+ end
+
+ header = r.new.header
+ assert_kind_of(ActionController::Live::Response::Header, header)
+ end
+
+ def test_parallel
+ latch = ActiveSupport::Concurrency::Latch.new
+
+ t = Thread.new {
+ @response.stream.write 'foo'
+ latch.await
+ @response.stream.close
+ }
+
+ @response.each do |part|
+ assert_equal 'foo', part
+ latch.release
+ end
+ assert t.join
+ end
+
+ def test_setting_body_populates_buffer
+ @response.body = 'omg'
+ @response.close
+ assert_equal ['omg'], @response.body_parts
+ end
+
+ def test_cache_control_is_set
+ @response.stream.write 'omg'
+ assert_equal 'no-cache', @response.headers['Cache-Control']
+ end
+
+ def test_content_length_is_removed
+ @response.headers['Content-Length'] = "1234"
+ @response.stream.write 'omg'
+ assert_nil @response.headers['Content-Length']
+ end
+
+ def test_headers_cannot_be_written_after_write
+ @response.stream.write 'omg'
+
+ assert @response.headers.frozen?
+ e = assert_raises(ActionDispatch::IllegalStateError) do
+ @response.headers['Content-Length'] = "zomg"
+ end
+
+ assert_equal 'header already sent', e.message
+ end
+
+ def test_headers_cannot_be_written_after_close
+ @response.stream.close
+
+ assert @response.headers.frozen?
+ e = assert_raises(ActionDispatch::IllegalStateError) do
+ @response.headers['Content-Length'] = "zomg"
+ end
+ assert_equal 'header already sent', e.message
+ end
+ end
+ end
+end
diff --git a/actionpack/test/dispatch/mapper_test.rb b/actionpack/test/dispatch/mapper_test.rb
index d3465589c1..58457b0c28 100644
--- a/actionpack/test/dispatch/mapper_test.rb
+++ b/actionpack/test/dispatch/mapper_test.rb
@@ -37,7 +37,7 @@ module ActionDispatch
end
def test_mapping_requirements
- options = { :controller => 'foo', :action => 'bar' }
+ options = { :controller => 'foo', :action => 'bar', :via => :get }
m = Mapper::Mapping.new FakeSet.new, {}, '/store/:name(*rest)', options
_, _, requirements, _ = m.to_route
assert_equal(/.+?/, requirements[:rest])
@@ -46,7 +46,7 @@ module ActionDispatch
def test_map_slash
fakeset = FakeSet.new
mapper = Mapper.new fakeset
- mapper.match '/', :to => 'posts#index', :as => :main
+ mapper.get '/', :to => 'posts#index', :as => :main
assert_equal '/', fakeset.conditions.first[:path_info]
end
@@ -55,14 +55,14 @@ module ActionDispatch
mapper = Mapper.new fakeset
# FIXME: is this a desired behavior?
- mapper.match '/one/two/', :to => 'posts#index', :as => :main
+ mapper.get '/one/two/', :to => 'posts#index', :as => :main
assert_equal '/one/two(.:format)', fakeset.conditions.first[:path_info]
end
def test_map_wildcard
fakeset = FakeSet.new
mapper = Mapper.new fakeset
- mapper.match '/*path', :to => 'pages#show'
+ mapper.get '/*path', :to => 'pages#show'
assert_equal '/*path(.:format)', fakeset.conditions.first[:path_info]
assert_equal(/.+?/, fakeset.requirements.first[:path])
end
@@ -70,7 +70,7 @@ module ActionDispatch
def test_map_wildcard_with_other_element
fakeset = FakeSet.new
mapper = Mapper.new fakeset
- mapper.match '/*path/foo/:bar', :to => 'pages#show'
+ mapper.get '/*path/foo/:bar', :to => 'pages#show'
assert_equal '/*path/foo/:bar(.:format)', fakeset.conditions.first[:path_info]
assert_nil fakeset.requirements.first[:path]
end
@@ -78,7 +78,7 @@ module ActionDispatch
def test_map_wildcard_with_multiple_wildcard
fakeset = FakeSet.new
mapper = Mapper.new fakeset
- mapper.match '/*foo/*bar', :to => 'pages#show'
+ mapper.get '/*foo/*bar', :to => 'pages#show'
assert_equal '/*foo/*bar(.:format)', fakeset.conditions.first[:path_info]
assert_nil fakeset.requirements.first[:foo]
assert_equal(/.+?/, fakeset.requirements.first[:bar])
@@ -87,7 +87,7 @@ module ActionDispatch
def test_map_wildcard_with_format_false
fakeset = FakeSet.new
mapper = Mapper.new fakeset
- mapper.match '/*path', :to => 'pages#show', :format => false
+ mapper.get '/*path', :to => 'pages#show', :format => false
assert_equal '/*path', fakeset.conditions.first[:path_info]
assert_nil fakeset.requirements.first[:path]
end
@@ -95,9 +95,18 @@ module ActionDispatch
def test_map_wildcard_with_format_true
fakeset = FakeSet.new
mapper = Mapper.new fakeset
- mapper.match '/*path', :to => 'pages#show', :format => true
+ mapper.get '/*path', :to => 'pages#show', :format => true
assert_equal '/*path.:format', fakeset.conditions.first[:path_info]
end
+
+ def test_raising_helpful_error_on_invalid_arguments
+ fakeset = FakeSet.new
+ mapper = Mapper.new fakeset
+ app = lambda { |env| [200, {}, [""]] }
+ assert_raises ArgumentError do
+ mapper.mount app
+ end
+ end
end
end
end
diff --git a/actionpack/test/dispatch/middleware_stack_test.rb b/actionpack/test/dispatch/middleware_stack_test.rb
index 4191ed1ff4..948a690979 100644
--- a/actionpack/test/dispatch/middleware_stack_test.rb
+++ b/actionpack/test/dispatch/middleware_stack_test.rb
@@ -45,7 +45,7 @@ class MiddlewareStackTest < ActiveSupport::TestCase
assert_equal BazMiddleware, @stack.last.klass
assert_equal([true, {:foo => "bar"}], @stack.last.args)
end
-
+
test "use should push middleware class with block arguments onto the stack" do
proc = Proc.new {}
assert_difference "@stack.size" do
@@ -54,7 +54,7 @@ class MiddlewareStackTest < ActiveSupport::TestCase
assert_equal BlockMiddleware, @stack.last.klass
assert_equal proc, @stack.last.block
end
-
+
test "insert inserts middleware at the integer index" do
@stack.insert(1, BazMiddleware)
assert_equal BazMiddleware, @stack[1].klass
@@ -87,6 +87,11 @@ class MiddlewareStackTest < ActiveSupport::TestCase
assert_equal FooMiddleware, @stack[0].klass
end
+ test "unshift adds a new middleware at the beginning of the stack" do
+ @stack.unshift :"MiddlewareStackTest::BazMiddleware"
+ assert_equal BazMiddleware, @stack.first.klass
+ end
+
test "raise an error on invalid index" do
assert_raise RuntimeError do
@stack.insert("HiyaMiddleware", BazMiddleware)
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index 0372c42920..3e83f3d4fa 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -75,6 +75,12 @@ class MimeTypeTest < ActiveSupport::TestCase
assert_equal expect, Mime::Type.parse(accept)
end
+ test "parse arbitarry media type parameters" do
+ accept = 'multipart/form-data; boundary="simple boundary"'
+ expect = [Mime::MULTIPART_FORM]
+ assert_equal expect, Mime::Type.parse(accept)
+ end
+
# Accept header send with user HTTP_USER_AGENT: Sunrise/0.42j (Windows XP)
test "parse 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"
@@ -86,7 +92,7 @@ class MimeTypeTest < ActiveSupport::TestCase
# (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1)
test "parse other broken acceptlines" 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 ]
+ 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
@@ -112,6 +118,20 @@ class MimeTypeTest < ActiveSupport::TestCase
end
end
+ test "register callbacks" do
+ begin
+ registered_mimes = []
+ Mime::Type.register_callback do |mime|
+ registered_mimes << mime
+ end
+
+ Mime::Type.register("text/foo", :foo)
+ assert_equal registered_mimes, [Mime::FOO]
+ ensure
+ Mime::Type.unregister(:FOO)
+ end
+ end
+
test "custom type with extension aliases" do
begin
Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"]
@@ -142,11 +162,11 @@ class MimeTypeTest < ActiveSupport::TestCase
types = Mime::SET.symbols.uniq - [:all, :iphone]
# 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.delete_if { |type| !Mime.const_defined?(type.upcase) }
types.each do |type|
- mime = Mime.const_get(type.to_s.upcase)
+ mime = Mime.const_get(type.upcase)
assert mime.respond_to?("#{type}?"), "#{mime.inspect} does not respond to #{type}?"
assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?"
invalid_types = types - [type]
@@ -164,10 +184,10 @@ class MimeTypeTest < ActiveSupport::TestCase
all_types = Mime::SET.symbols
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) }
+ all_types.delete_if { |type| !Mime.const_defined?(type.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}" }
+ assert verified.each { |type| assert Mime.const_get(type.upcase).verify_request?, "Verifiable Mime Type is not verified: #{type.inspect}" }
+ assert unverified.each { |type| assert !Mime.const_get(type.upcase).verify_request?, "Nonverifiable Mime Type is verified: #{type.inspect}" }
end
test "references gives preference to symbols before strings" do
diff --git a/actionpack/test/dispatch/mount_test.rb b/actionpack/test/dispatch/mount_test.rb
index f7a746120e..3b008fdff0 100644
--- a/actionpack/test/dispatch/mount_test.rb
+++ b/actionpack/test/dispatch/mount_test.rb
@@ -22,6 +22,7 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
mount SprocketsApp => "/shorthand"
mount FakeEngine, :at => "/fakeengine"
+ mount FakeEngine, :at => "/getfake", :via => :get
scope "/its_a" do
mount SprocketsApp, :at => "/sprocket"
@@ -37,6 +38,11 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
assert_equal "/sprockets -- /omg", response.body
end
+ def test_mounting_works_with_nested_script_name
+ get "/foo/sprockets/omg", {}, 'SCRIPT_NAME' => '/foo', 'PATH_INFO' => '/sprockets/omg'
+ assert_equal "/foo/sprockets -- /omg", response.body
+ end
+
def test_mounting_works_with_scope
get "/its_a/sprocket/omg"
assert_equal "/its_a/sprocket -- /omg", response.body
@@ -47,6 +53,14 @@ class TestRoutingMount < ActionDispatch::IntegrationTest
assert_equal "/shorthand -- /omg", response.body
end
+ def test_mounting_works_with_via
+ get "/getfake"
+ assert_equal "OK", response.body
+
+ post "/getfake"
+ assert_response :not_found
+ end
+
def test_with_fake_engine_does_not_call_invalid_method
get "/fakeengine"
assert_equal "OK", response.body
diff --git a/actionpack/test/dispatch/prefix_generation_test.rb b/actionpack/test/dispatch/prefix_generation_test.rb
index bd5b5edab0..cfbf970a37 100644
--- a/actionpack/test/dispatch/prefix_generation_test.rb
+++ b/actionpack/test/dispatch/prefix_generation_test.rb
@@ -25,12 +25,12 @@ module TestGenerationPrefix
@routes ||= begin
routes = ActionDispatch::Routing::RouteSet.new
routes.draw do
- match "/posts/:id", :to => "inside_engine_generating#show", :as => :post
- match "/posts", :to => "inside_engine_generating#index", :as => :posts
- match "/url_to_application", :to => "inside_engine_generating#url_to_application"
- match "/polymorphic_path_for_engine", :to => "inside_engine_generating#polymorphic_path_for_engine"
- match "/conflicting_url", :to => "inside_engine_generating#conflicting"
- match "/foo", :to => "never#invoked", :as => :named_helper_that_should_be_invoked_only_in_respond_to_test
+ get "/posts/:id", :to => "inside_engine_generating#show", :as => :post
+ get "/posts", :to => "inside_engine_generating#index", :as => :posts
+ get "/url_to_application", :to => "inside_engine_generating#url_to_application"
+ get "/polymorphic_path_for_engine", :to => "inside_engine_generating#polymorphic_path_for_engine"
+ get "/conflicting_url", :to => "inside_engine_generating#conflicting"
+ get "/foo", :to => "never#invoked", :as => :named_helper_that_should_be_invoked_only_in_respond_to_test
end
routes
@@ -51,12 +51,13 @@ module TestGenerationPrefix
scope "/:omg", :omg => "awesome" do
mount BlogEngine => "/blog", :as => "blog_engine"
end
- match "/posts/:id", :to => "outside_engine_generating#post", :as => :post
- match "/generate", :to => "outside_engine_generating#index"
- match "/polymorphic_path_for_app", :to => "outside_engine_generating#polymorphic_path_for_app"
- match "/polymorphic_path_for_engine", :to => "outside_engine_generating#polymorphic_path_for_engine"
- match "/polymorphic_with_url_for", :to => "outside_engine_generating#polymorphic_with_url_for"
- match "/conflicting_url", :to => "outside_engine_generating#conflicting"
+ get "/posts/:id", :to => "outside_engine_generating#post", :as => :post
+ get "/generate", :to => "outside_engine_generating#index"
+ get "/polymorphic_path_for_app", :to => "outside_engine_generating#polymorphic_path_for_app"
+ get "/polymorphic_path_for_engine", :to => "outside_engine_generating#polymorphic_path_for_engine"
+ get "/polymorphic_with_url_for", :to => "outside_engine_generating#polymorphic_with_url_for"
+ get "/conflicting_url", :to => "outside_engine_generating#conflicting"
+ get "/ivar_usage", :to => "outside_engine_generating#ivar_usage"
root :to => "outside_engine_generating#index"
end
@@ -125,6 +126,11 @@ module TestGenerationPrefix
def conflicting
render :text => "application"
end
+
+ def ivar_usage
+ @blog_engine = "Not the engine route helper"
+ render :text => blog_engine.post_path(:id => 1)
+ end
end
class EngineObject
@@ -166,18 +172,6 @@ module TestGenerationPrefix
assert_equal "/generate", last_response.body
end
- test "[ENGINE] generating application's url includes default_url_options[:script_name]" do
- RailsApplication.routes.default_url_options = {:script_name => "/something"}
- get "/pure-awesomeness/blog/url_to_application"
- assert_equal "/something/generate", last_response.body
- end
-
- test "[ENGINE] generating application's url should give higher priority to default_url_options[:script_name]" do
- RailsApplication.routes.default_url_options = {:script_name => "/something"}
- get "/pure-awesomeness/blog/url_to_application", {}, 'SCRIPT_NAME' => '/foo'
- assert_equal "/something/generate", last_response.body
- end
-
test "[ENGINE] generating engine's url with polymorphic path" do
get "/pure-awesomeness/blog/polymorphic_path_for_engine"
assert_equal "/pure-awesomeness/blog/posts/1", last_response.body
@@ -200,12 +194,6 @@ module TestGenerationPrefix
assert_equal "/something/awesome/blog/posts/1", last_response.body
end
- test "[APP] generating engine's route should give higher priority to default_url_options[:script_name]" do
- RailsApplication.routes.default_url_options = {:script_name => "/something"}
- get "/generate", {}, 'SCRIPT_NAME' => "/foo"
- assert_equal "/something/awesome/blog/posts/1", last_response.body
- end
-
test "[APP] generating engine's url with polymorphic path" do
get "/polymorphic_path_for_engine"
assert_equal "/awesome/blog/posts/1", last_response.body
@@ -221,6 +209,11 @@ module TestGenerationPrefix
assert_equal "http://example.org/awesome/blog/posts/1", last_response.body
end
+ test "[APP] instance variable with same name as engine" do
+ get "/ivar_usage"
+ assert_equal "/awesome/blog/posts/1", last_response.body
+ end
+
# Inside any Object
test "[OBJECT] proxy route should override respond_to?() as expected" do
assert_respond_to blog_engine, :named_helper_that_should_be_invoked_only_in_respond_to_test_path
@@ -282,7 +275,7 @@ module TestGenerationPrefix
@routes ||= begin
routes = ActionDispatch::Routing::RouteSet.new
routes.draw do
- match "/posts/:id", :to => "posts#show", :as => :post
+ get "/posts/:id", :to => "posts#show", :as => :post
end
routes
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index ae425dd406..302bff0696 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -65,7 +65,7 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do
- match ':action', :to => ::JsonParamsParsingTest::TestController
+ post ':action', :to => ::JsonParamsParsingTest::TestController
end
yield
end
@@ -118,7 +118,7 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing(controller)
with_routing do |set|
set.draw do
- match ':action', :to => controller
+ post ':action', :to => controller
end
yield
end
diff --git a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
index d144f013f5..63c5ea26a6 100644
--- a/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/multipart_params_parsing_test.rb
@@ -144,7 +144,7 @@ class MultipartParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do
- match ':action', :to => 'multipart_params_parsing_test/test'
+ post ':action', :to => 'multipart_params_parsing_test/test'
end
yield
end
diff --git a/actionpack/test/dispatch/request/query_string_parsing_test.rb b/actionpack/test/dispatch/request/query_string_parsing_test.rb
index f6a1475d04..3cb430d83d 100644
--- a/actionpack/test/dispatch/request/query_string_parsing_test.rb
+++ b/actionpack/test/dispatch/request/query_string_parsing_test.rb
@@ -81,7 +81,16 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
end
test "query string without equal" do
- assert_parses({ "action" => nil }, "action")
+ assert_parses({"action" => nil}, "action")
+ assert_parses({"action" => {"foo" => nil}}, "action[foo]")
+ assert_parses({"action" => {"foo" => { "bar" => nil }}}, "action[foo][bar]")
+ assert_parses({"action" => {"foo" => { "bar" => [] }}}, "action[foo][bar][]")
+ assert_parses({"action" => {"foo" => []}}, "action[foo][]")
+ assert_parses({"action"=>{"foo"=>[{"bar"=>nil}]}}, "action[foo][][bar]")
+ end
+
+ def test_array_parses_without_nil
+ assert_parses({"action" => ['1']}, "action[]=1&action[]")
end
test "query string with empty key" do
@@ -105,11 +114,22 @@ class QueryStringParsingTest < ActionDispatch::IntegrationTest
)
end
+ test "ambiguous query string returns a bad request" do
+ with_routing do |set|
+ set.draw do
+ get ':action', :to => ::QueryStringParsingTest::TestController
+ end
+
+ get "/parse", nil, "QUERY_STRING" => "foo[]=bar&foo[4]=bar"
+ assert_response :bad_request
+ end
+ end
+
private
def assert_parses(expected, actual)
with_routing do |set|
set.draw do
- match ':action', :to => ::QueryStringParsingTest::TestController
+ get ':action', :to => ::QueryStringParsingTest::TestController
end
get "/parse", actual
diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb
new file mode 100644
index 0000000000..3f36d4f1a9
--- /dev/null
+++ b/actionpack/test/dispatch/request/session_test.rb
@@ -0,0 +1,73 @@
+require 'abstract_unit'
+require 'action_dispatch/middleware/session/abstract_store'
+
+module ActionDispatch
+ class Request
+ class SessionTest < ActiveSupport::TestCase
+ def test_create_adds_itself_to_env
+ env = {}
+ s = Session.create(store, env, {})
+ assert_equal s, env[Rack::Session::Abstract::ENV_SESSION_KEY]
+ end
+
+ def test_to_hash
+ env = {}
+ s = Session.create(store, env, {})
+ s['foo'] = 'bar'
+ assert_equal 'bar', s['foo']
+ assert_equal({'foo' => 'bar'}, s.to_hash)
+ end
+
+ def test_create_merges_old
+ env = {}
+ s = Session.create(store, env, {})
+ s['foo'] = 'bar'
+
+ s1 = Session.create(store, env, {})
+ refute_equal s, s1
+ assert_equal 'bar', s1['foo']
+ end
+
+ def test_find
+ env = {}
+ assert_nil Session.find(env)
+
+ s = Session.create(store, env, {})
+ assert_equal s, Session.find(env)
+ end
+
+ def test_keys
+ env = {}
+ s = Session.create(store, env, {})
+ s['rails'] = 'ftw'
+ s['adequate'] = 'awesome'
+ assert_equal %w[rails adequate], s.keys
+ end
+
+ def test_values
+ env = {}
+ s = Session.create(store, env, {})
+ s['rails'] = 'ftw'
+ s['adequate'] = 'awesome'
+ assert_equal %w[ftw awesome], s.values
+ end
+
+ def test_clear
+ env = {}
+ s = Session.create(store, env, {})
+ s['rails'] = 'ftw'
+ s['adequate'] = 'awesome'
+ s.clear
+ assert_equal([], s.values)
+ end
+
+ private
+ def store
+ Class.new {
+ def load_session(env); [1, {}]; end
+ def session_exists?(env); true; end
+ }.new
+ end
+ 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
index 05569561d2..e9b59f55a7 100644
--- a/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/url_encoded_params_parsing_test.rb
@@ -126,11 +126,22 @@ class UrlEncodedParamsParsingTest < ActionDispatch::IntegrationTest
assert_parses expected, query
end
+ test "ambiguous params returns a bad request" do
+ with_routing do |set|
+ set.draw do
+ post ':action', :to => ::UrlEncodedParamsParsingTest::TestController
+ end
+
+ post "/parse", "foo[]=bar&foo[4]=bar"
+ assert_response :bad_request
+ end
+ end
+
private
def with_test_routing
with_routing do |set|
set.draw do
- match ':action', :to => ::UrlEncodedParamsParsingTest::TestController
+ post ':action', :to => ::UrlEncodedParamsParsingTest::TestController
end
yield
end
diff --git a/actionpack/test/dispatch/request/xml_params_parsing_test.rb b/actionpack/test/dispatch/request/xml_params_parsing_test.rb
index afd400c2a9..84823e2896 100644
--- a/actionpack/test/dispatch/request/xml_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/xml_params_parsing_test.rb
@@ -106,7 +106,7 @@ class XmlParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do
- match ':action', :to => ::XmlParamsParsingTest::TestController
+ post ':action', :to => ::XmlParamsParsingTest::TestController
end
yield
end
@@ -155,7 +155,7 @@ class RootLessXmlParamsParsingTest < ActionDispatch::IntegrationTest
def with_test_routing
with_routing do |set|
set.draw do
- match ':action', :to => ::RootLessXmlParamsParsingTest::TestController
+ post ':action', :to => ::RootLessXmlParamsParsingTest::TestController
end
yield
end
diff --git a/actionpack/test/dispatch/request_id_test.rb b/actionpack/test/dispatch/request_id_test.rb
index 4b98cd32f2..a8050b4fab 100644
--- a/actionpack/test/dispatch/request_id_test.rb
+++ b/actionpack/test/dispatch/request_id_test.rb
@@ -52,7 +52,7 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest
def with_test_route_set
with_routing do |set|
set.draw do
- match '/', :to => ::RequestIdResponseTest::TestController.action(:index)
+ get '/', :to => ::RequestIdResponseTest::TestController.action(:index)
end
@app = self.class.build_app(set) do |middleware|
@@ -62,4 +62,4 @@ class RequestIdResponseTest < ActionDispatch::IntegrationTest
yield
end
end
-end \ No newline at end of file
+end
diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb
index 6c8b22c47f..a2b9571660 100644
--- a/actionpack/test/dispatch/request_test.rb
+++ b/actionpack/test/dispatch/request_test.rb
@@ -35,37 +35,40 @@ class RequestTest < ActiveSupport::TestCase
assert_equal '1.2.3.4', request.remote_ip
request = stub_request 'REMOTE_ADDR' => '1.2.3.4',
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
+ 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
assert_equal '3.4.5.6', request.remote_ip
request = stub_request 'REMOTE_ADDR' => '127.0.0.1',
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
+ 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
assert_equal '3.4.5.6', request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6,unknown'
assert_equal '3.4.5.6', request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '172.16.0.1,3.4.5.6'
- assert_equal '3.4.5.6', request.remote_ip
+ assert_equal nil, request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '192.168.0.1,3.4.5.6'
- assert_equal '3.4.5.6', request.remote_ip
+ assert_equal nil, request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '10.0.0.1,3.4.5.6'
- assert_equal '3.4.5.6', request.remote_ip
+ assert_equal nil, request.remote_ip
request = stub_request '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
+ assert_equal nil, request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '127.0.0.1,3.4.5.6'
- assert_equal '3.4.5.6', request.remote_ip
+ assert_equal nil, request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,192.168.0.1'
- assert_equal 'unknown', request.remote_ip
+ assert_equal nil, request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 172.31.4.4'
assert_equal '3.4.5.6', request.remote_ip
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
+ assert_equal nil, request.remote_ip
+
request = stub_request 'HTTP_X_FORWARDED_FOR' => '1.1.1.1',
'HTTP_CLIENT_IP' => '2.2.2.2'
e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
@@ -89,6 +92,68 @@ class RequestTest < ActiveSupport::TestCase
assert_equal '9.9.9.9', request.remote_ip
end
+ test "remote ip v6" do
+ request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
+ 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
+
+ request = stub_request 'REMOTE_ADDR' => '::1',
+ 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '::1, ::1, fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,::1'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334, fe80:0000:0000:0000:0202:b3ff:fe1e:8329, ::1, fc00::'
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'not_ip_address'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329',
+ 'HTTP_CLIENT_IP' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+ e = assert_raise(ActionDispatch::RemoteIp::IpSpoofAttackError) {
+ request.remote_ip
+ }
+ assert_match(/IP spoofing attack/, e.message)
+ assert_match(/HTTP_X_FORWARDED_FOR="fe80:0000:0000:0000:0202:b3ff:fe1e:8329"/, e.message)
+ assert_match(/HTTP_CLIENT_IP="2001:0db8:85a3:0000:0000:8a2e:0370:7334"/, 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.
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329',
+ 'HTTP_CLIENT_IP' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
+ :ip_spoofing_check => false
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+ assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
+ end
+
test "remote ip when the remote ip middleware returns nil" do
request = stub_request 'REMOTE_ADDR' => '127.0.0.1'
assert_equal '127.0.0.1', request.remote_ip
@@ -97,29 +162,47 @@ class RequestTest < ActiveSupport::TestCase
test "remote ip with user specified trusted proxies String" do
@trusted_proxies = "67.205.106.73"
- request = stub_request 'REMOTE_ADDR' => '67.205.106.73',
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
+ request = stub_request 'REMOTE_ADDR' => '3.4.5.6',
+ 'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
assert_equal '3.4.5.6', request.remote_ip
request = stub_request 'REMOTE_ADDR' => '172.16.0.1,67.205.106.73',
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
- assert_equal '3.4.5.6', request.remote_ip
+ 'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
+ assert_equal '172.16.0.1', request.remote_ip
- request = stub_request 'REMOTE_ADDR' => '67.205.106.73,172.16.0.1',
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
- assert_equal '3.4.5.6', request.remote_ip
-
- request = stub_request 'REMOTE_ADDR' => '67.205.106.74,172.16.0.1',
- 'HTTP_X_FORWARDED_FOR' => '3.4.5.6'
+ request = stub_request 'REMOTE_ADDR' => '67.205.106.73,3.4.5.6',
+ 'HTTP_X_FORWARDED_FOR' => '67.205.106.73'
assert_equal '3.4.5.6', request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,67.205.106.73'
- assert_equal 'unknown', request.remote_ip
+ assert_equal nil, request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '3.4.5.6, 9.9.9.9, 10.0.0.1, 67.205.106.73'
assert_equal '3.4.5.6', request.remote_ip
end
+ test "remote ip v6 with user specified trusted proxies String" do
+ @trusted_proxies = 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+
+ request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
+ 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334',
+ 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'REMOTE_ADDR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,::1',
+ 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329', request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'unknown,fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal nil, request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329,2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+ assert_equal nil, request.remote_ip
+ end
+
test "remote ip with user specified trusted proxies Regexp" do
@trusted_proxies = /^67\.205\.106\.73$/i
@@ -128,7 +211,18 @@ class RequestTest < ActiveSupport::TestCase
assert_equal '3.4.5.6', request.remote_ip
request = stub_request 'HTTP_X_FORWARDED_FOR' => '67.205.106.73, 10.0.0.1, 9.9.9.9, 3.4.5.6'
- assert_equal '10.0.0.1', request.remote_ip
+ assert_equal nil, request.remote_ip
+ end
+
+ test "remote ip v6 with user specified trusted proxies Regexp" do
+ @trusted_proxies = /^fe80:0000:0000:0000:0202:b3ff:fe1e:8329$/i
+
+ request = stub_request 'REMOTE_ADDR' => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
+ 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329'
+ assert_equal '2001:0db8:85a3:0000:0000:8a2e:0370:7334', request.remote_ip
+
+ request = stub_request 'HTTP_X_FORWARDED_FOR' => 'fe80:0000:0000:0000:0202:b3ff:fe1e:8329, 2001:0db8:85a3:0000:0000:8a2e:0370:7334'
+ assert_equal nil, request.remote_ip
end
test "domains" do
@@ -367,14 +461,6 @@ class RequestTest < ActiveSupport::TestCase
end
end
- test "head masquerading as get" do
- request = stub_request 'REQUEST_METHOD' => 'GET', "rack.methodoverride.original_method" => "HEAD"
- assert_equal "HEAD", request.method
- assert_equal "GET", request.request_method
- assert request.get?
- assert request.head?
- end
-
test "post masquerading as patch" do
request = stub_request 'REQUEST_METHOD' => 'PATCH', "rack.methodoverride.original_method" => "POST"
assert_equal "POST", request.method
@@ -467,7 +553,7 @@ class RequestTest < ActiveSupport::TestCase
begin
request = stub_request(mock_rack_env)
request.parameters
- rescue TypeError
+ rescue ActionController::BadRequest
# rack will raise a TypeError when parsing this query string
end
assert_equal({}, request.parameters)
@@ -660,6 +746,45 @@ class RequestTest < ActiveSupport::TestCase
assert_equal "/foo?bar", path
end
+ test "if_none_match_etags none" do
+ request = stub_request
+
+ assert_equal nil, request.if_none_match
+ assert_equal [], request.if_none_match_etags
+ assert !request.etag_matches?("foo")
+ assert !request.etag_matches?(nil)
+ end
+
+ test "if_none_match_etags single" do
+ header = 'the-etag'
+ request = stub_request('HTTP_IF_NONE_MATCH' => header)
+
+ assert_equal header, request.if_none_match
+ assert_equal [header], request.if_none_match_etags
+ assert request.etag_matches?("the-etag")
+ end
+
+ test "if_none_match_etags quoted single" do
+ header = '"the-etag"'
+ request = stub_request('HTTP_IF_NONE_MATCH' => header)
+
+ assert_equal header, request.if_none_match
+ assert_equal ['the-etag'], request.if_none_match_etags
+ assert request.etag_matches?("the-etag")
+ end
+
+ test "if_none_match_etags multiple" do
+ header = 'etag1, etag2, "third etag", "etag4"'
+ expected = ['etag1', 'etag2', 'third etag', 'etag4']
+ request = stub_request('HTTP_IF_NONE_MATCH' => header)
+
+ assert_equal header, request.if_none_match
+ assert_equal expected, request.if_none_match_etags
+ expected.each do |etag|
+ assert request.etag_matches?(etag), etag
+ end
+ end
+
protected
def stub_request(env = {})
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 82d1200f8e..185a9e9b18 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -5,6 +5,35 @@ class ResponseTest < ActiveSupport::TestCase
@response = ActionDispatch::Response.new
end
+ def test_can_wait_until_commit
+ t = Thread.new {
+ @response.await_commit
+ }
+ @response.commit!
+ assert @response.committed?
+ assert t.join(0.5)
+ end
+
+ def test_stream_close
+ @response.stream.close
+ assert @response.stream.closed?
+ end
+
+ def test_stream_write
+ @response.stream.write "foo"
+ @response.stream.close
+ assert_equal "foo", @response.body
+ end
+
+ def test_write_after_close
+ @response.stream.close
+
+ e = assert_raises(IOError) do
+ @response.stream.write "omg"
+ end
+ assert_equal "closed stream", e.message
+ end
+
def test_response_body_encoding
body = ["hello".encode('utf-8')]
response = ActionDispatch::Response.new 200, {}, body
@@ -147,6 +176,42 @@ class ResponseTest < ActiveSupport::TestCase
ActionDispatch::Response.default_charset = original
end
end
+
+ test "read x_frame_options, x_content_type_options and x_xss_protection" do
+ begin
+ ActionDispatch::Response.default_headers = {
+ 'X-Frame-Options' => 'DENY',
+ 'X-Content-Type-Options' => 'nosniff',
+ 'X-XSS-Protection' => '1;'
+ }
+ resp = ActionDispatch::Response.new.tap { |response|
+ response.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('DENY', resp.headers['X-Frame-Options'])
+ assert_equal('nosniff', resp.headers['X-Content-Type-Options'])
+ assert_equal('1;', resp.headers['X-XSS-Protection'])
+ ensure
+ ActionDispatch::Response.default_headers = nil
+ end
+ end
+
+ test "read custom default_header" do
+ begin
+ ActionDispatch::Response.default_headers = {
+ 'X-XX-XXXX' => 'Here is my phone number'
+ }
+ resp = ActionDispatch::Response.new.tap { |response|
+ response.body = 'Hello'
+ }
+ resp.to_a
+
+ assert_equal('Here is my phone number', resp.headers['X-XX-XXXX'])
+ ensure
+ ActionDispatch::Response.default_headers = nil
+ end
+ end
end
class ResponseIntegrationTest < ActionDispatch::IntegrationTest
diff --git a/actionpack/test/dispatch/routing/concerns_test.rb b/actionpack/test/dispatch/routing/concerns_test.rb
new file mode 100644
index 0000000000..9f37701656
--- /dev/null
+++ b/actionpack/test/dispatch/routing/concerns_test.rb
@@ -0,0 +1,119 @@
+require 'abstract_unit'
+
+class RoutingConcernsTest < ActionDispatch::IntegrationTest
+ class Reviewable
+ def self.call(mapper, options = {})
+ mapper.resources :reviews, options
+ end
+ end
+
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ concern :commentable do |options|
+ resources :comments, options
+ end
+
+ concern :image_attachable do
+ resources :images, only: :index
+ end
+
+ concern :reviewable, Reviewable
+
+ resources :posts, concerns: [:commentable, :image_attachable, :reviewable] do
+ resource :video, concerns: :commentable do
+ concerns :reviewable, as: :video_reviews
+ end
+ end
+
+ resource :picture, concerns: :commentable do
+ resources :posts, concerns: :commentable
+ end
+
+ scope "/videos" do
+ concerns :commentable, except: :destroy
+ end
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ def test_accessing_concern_from_resources
+ get "/posts/1/comments"
+ assert_equal "200", @response.code
+ assert_equal "/posts/1/comments", post_comments_path(post_id: 1)
+ end
+
+ def test_accessing_concern_from_resource
+ get "/picture/comments"
+ assert_equal "200", @response.code
+ assert_equal "/picture/comments", picture_comments_path
+ end
+
+ def test_accessing_concern_from_nested_resource
+ get "/posts/1/video/comments"
+ assert_equal "200", @response.code
+ assert_equal "/posts/1/video/comments", post_video_comments_path(post_id: 1)
+ end
+
+ def test_accessing_concern_from_nested_resources
+ get "/picture/posts/1/comments"
+ assert_equal "200", @response.code
+ assert_equal "/picture/posts/1/comments", picture_post_comments_path(post_id: 1)
+ end
+
+ def test_accessing_concern_from_resources_with_more_than_one_concern
+ get "/posts/1/images"
+ assert_equal "200", @response.code
+ assert_equal "/posts/1/images", post_images_path(post_id: 1)
+ end
+
+ def test_accessing_concern_from_resources_using_only_option
+ get "/posts/1/image/1"
+ assert_equal "404", @response.code
+ end
+
+ def test_accessing_callable_concern_
+ get "/posts/1/reviews/1"
+ assert_equal "200", @response.code
+ assert_equal "/posts/1/reviews/1", post_review_path(post_id: 1, id: 1)
+ end
+
+ def test_callable_concerns_accept_options
+ get "/posts/1/video/reviews/1"
+ assert_equal "200", @response.code
+ assert_equal "/posts/1/video/reviews/1", post_video_video_review_path(post_id: 1, id: 1)
+ end
+
+ def test_accessing_concern_from_a_scope
+ get "/videos/comments"
+ assert_equal "200", @response.code
+ end
+
+ def test_concerns_accept_options
+ delete "/videos/comments/1"
+ assert_equal "404", @response.code
+ end
+
+ def test_with_an_invalid_concern_name
+ e = assert_raise ArgumentError do
+ ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ resources :posts, concerns: :foo
+ end
+ end
+ end
+
+ assert_equal "No concern named foo was found!", e.message
+ end
+
+ def test_concerns_executes_block_in_context_of_current_mapper
+ mapper = ActionDispatch::Routing::Mapper.new(ActionDispatch::Routing::RouteSet.new)
+ mapper.concern :test_concern do
+ resources :things
+ return self
+ end
+
+ assert_equal mapper, mapper.concerns(:test_concern)
+ end
+end
diff --git a/actionpack/test/dispatch/routing/inspector_test.rb b/actionpack/test/dispatch/routing/inspector_test.rb
new file mode 100644
index 0000000000..97fc4f3e4b
--- /dev/null
+++ b/actionpack/test/dispatch/routing/inspector_test.rb
@@ -0,0 +1,170 @@
+require 'minitest/autorun'
+require 'action_controller'
+require 'rails/engine'
+require 'action_dispatch/routing/inspector'
+
+module ActionDispatch
+ module Routing
+ class RoutesInspectorTest < ActiveSupport::TestCase
+ def setup
+ @set = ActionDispatch::Routing::RouteSet.new
+ @inspector = ActionDispatch::Routing::RoutesInspector.new
+ app = ActiveSupport::OrderedOptions.new
+ app.config = ActiveSupport::OrderedOptions.new
+ app.config.assets = ActiveSupport::OrderedOptions.new
+ app.config.assets.prefix = '/sprockets'
+ Rails.stubs(:application).returns(app)
+ Rails.stubs(:env).returns("development")
+ end
+
+ def draw(&block)
+ @set.draw(&block)
+ @inspector.format(@set.routes)
+ end
+
+ def test_displaying_routes_for_engines
+ engine = Class.new(Rails::Engine) do
+ def self.to_s
+ "Blog::Engine"
+ end
+ end
+ engine.routes.draw do
+ get '/cart', :to => 'cart#show'
+ end
+
+ output = draw do
+ get '/custom/assets', :to => 'custom_assets#show'
+ mount engine => "/blog", :as => "blog"
+ end
+
+ expected = [
+ "custom_assets GET /custom/assets(.:format) custom_assets#show",
+ " blog /blog Blog::Engine",
+ "\nRoutes for Blog::Engine:",
+ "cart GET /cart(.:format) cart#show"
+ ]
+ assert_equal expected, output
+ end
+
+ def test_cart_inspect
+ output = draw do
+ get '/cart', :to => 'cart#show'
+ end
+ assert_equal ["cart GET /cart(.:format) cart#show"], output
+ end
+
+ def test_inspect_shows_custom_assets
+ output = draw do
+ get '/custom/assets', :to => 'custom_assets#show'
+ end
+ assert_equal ["custom_assets GET /custom/assets(.:format) custom_assets#show"], output
+ end
+
+ def test_inspect_routes_shows_resources_route
+ output = draw do
+ resources :articles
+ end
+ expected = [
+ " articles GET /articles(.:format) articles#index",
+ " POST /articles(.:format) articles#create",
+ " new_article GET /articles/new(.:format) articles#new",
+ "edit_article GET /articles/:id/edit(.:format) articles#edit",
+ " article GET /articles/:id(.:format) articles#show",
+ " PATCH /articles/:id(.:format) articles#update",
+ " PUT /articles/:id(.:format) articles#update",
+ " DELETE /articles/:id(.:format) articles#destroy" ]
+ assert_equal expected, output
+ end
+
+ def test_inspect_routes_shows_root_route
+ output = draw do
+ root :to => 'pages#main'
+ end
+ assert_equal ["root GET / pages#main"], output
+ end
+
+ def test_inspect_routes_shows_dynamic_action_route
+ output = draw do
+ get 'api/:action' => 'api'
+ end
+ assert_equal [" GET /api/:action(.:format) api#:action"], output
+ end
+
+ def test_inspect_routes_shows_controller_and_action_only_route
+ output = draw do
+ get ':controller/:action'
+ end
+ assert_equal [" GET /:controller/:action(.:format) :controller#:action"], output
+ end
+
+ def test_inspect_routes_shows_controller_and_action_route_with_constraints
+ output = draw do
+ get ':controller(/:action(/:id))', :id => /\d+/
+ end
+ assert_equal [" GET /:controller(/:action(/:id))(.:format) :controller#:action {:id=>/\\d+/}"], output
+ end
+
+ def test_rake_routes_shows_route_with_defaults
+ output = draw do
+ get 'photos/:id' => 'photos#show', :defaults => {:format => 'jpg'}
+ end
+ assert_equal [%Q[ GET /photos/:id(.:format) photos#show {:format=>"jpg"}]], output
+ end
+
+ def test_rake_routes_shows_route_with_constraints
+ output = draw do
+ get 'photos/:id' => 'photos#show', :id => /[A-Z]\d{5}/
+ end
+ assert_equal [" GET /photos/:id(.:format) photos#show {:id=>/[A-Z]\\d{5}/}"], output
+ end
+
+ class RackApp
+ def self.call(env)
+ end
+ end
+
+ def test_rake_routes_shows_route_with_rack_app
+ output = draw do
+ get 'foo/:id' => RackApp, :id => /[A-Z]\d{5}/
+ end
+ assert_equal [" GET /foo/:id(.:format) #{RackApp.name} {:id=>/[A-Z]\\d{5}/}"], output
+ end
+
+ def test_rake_routes_shows_route_with_rack_app_nested_with_dynamic_constraints
+ constraint = Class.new do
+ def to_s
+ "( my custom constraint )"
+ end
+ end
+
+ output = draw do
+ scope :constraint => constraint.new do
+ mount RackApp => '/foo'
+ end
+ end
+
+ assert_equal [" /foo #{RackApp.name} {:constraint=>( my custom constraint )}"], output
+ end
+
+ def test_rake_routes_dont_show_app_mounted_in_assets_prefix
+ output = draw do
+ get '/sprockets' => RackApp
+ end
+ assert_no_match(/RackApp/, output.first)
+ assert_no_match(/\/sprockets/, output.first)
+ end
+
+ def test_redirect
+ output = draw do
+ get "/foo" => redirect("/foo/bar"), :constraints => { :subdomain => "admin" }
+ get "/bar" => redirect(path: "/foo/bar", status: 307)
+ get "/foobar" => redirect{ "/foo/bar" }
+ end
+
+ assert_equal " foo GET /foo(.:format) redirect(301, /foo/bar) {:subdomain=>\"admin\"}", output[0]
+ assert_equal " bar GET /bar(.:format) redirect(307, path: /foo/bar)", output[1]
+ assert_equal "foobar GET /foobar(.:format) redirect(301)", output[2]
+ end
+ end
+ end
+end
diff --git a/actionpack/test/dispatch/routing_assertions_test.rb b/actionpack/test/dispatch/routing_assertions_test.rb
index 9f95d82129..aea4489852 100644
--- a/actionpack/test/dispatch/routing_assertions_test.rb
+++ b/actionpack/test/dispatch/routing_assertions_test.rb
@@ -3,6 +3,7 @@ require 'controller/fake_controllers'
class SecureArticlesController < ArticlesController; end
class BlockArticlesController < ArticlesController; end
+class QueryArticlesController < ArticlesController; end
class RoutingAssertionsTest < ActionController::TestCase
@@ -18,6 +19,10 @@ class RoutingAssertionsTest < ActionController::TestCase
scope 'block', :constraints => lambda { |r| r.ssl? } do
resources :articles, :controller => 'block_articles'
end
+
+ scope 'query', :constraints => lambda { |r| r.params[:use_query] == 'true' } do
+ resources :articles, :controller => 'query_articles'
+ end
end
end
@@ -42,26 +47,33 @@ class RoutingAssertionsTest < ActionController::TestCase
def test_assert_recognizes_with_extras
assert_recognizes({ :controller => 'articles', :action => 'index', :page => '1' }, '/articles', { :page => '1' })
end
-
+
def test_assert_recognizes_with_method
assert_recognizes({ :controller => 'articles', :action => 'create' }, { :path => '/articles', :method => :post })
assert_recognizes({ :controller => 'articles', :action => 'update', :id => '1' }, { :path => '/articles/1', :method => :put })
end
def test_assert_recognizes_with_hash_constraint
- assert_raise(ActionController::RoutingError) do
+ assert_raise(Assertion) do
assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'http://test.host/secure/articles')
end
- assert_recognizes({ :controller => 'secure_articles', :action => 'index' }, 'https://test.host/secure/articles')
+ assert_recognizes({ :controller => 'secure_articles', :action => 'index', :protocol => 'https://' }, 'https://test.host/secure/articles')
end
def test_assert_recognizes_with_block_constraint
- assert_raise(ActionController::RoutingError) do
+ assert_raise(Assertion) do
assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'http://test.host/block/articles')
end
assert_recognizes({ :controller => 'block_articles', :action => 'index' }, 'https://test.host/block/articles')
end
+ def test_assert_recognizes_with_query_constraint
+ assert_raise(Assertion) do
+ assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'false' }, '/query/articles', { :use_query => 'false' })
+ end
+ assert_recognizes({ :controller => 'query_articles', :action => 'index', :use_query => 'true' }, '/query/articles', { :use_query => 'true' })
+ end
+
def test_assert_routing
assert_routing('/articles', :controller => 'articles', :action => 'index')
end
@@ -75,14 +87,14 @@ class RoutingAssertionsTest < ActionController::TestCase
end
def test_assert_routing_with_hash_constraint
- assert_raise(ActionController::RoutingError) do
+ assert_raise(Assertion) do
assert_routing('http://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' })
end
- assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index' })
+ assert_routing('https://test.host/secure/articles', { :controller => 'secure_articles', :action => 'index', :protocol => 'https://' })
end
def test_assert_routing_with_block_constraint
- assert_raise(ActionController::RoutingError) do
+ assert_raise(Assertion) do
assert_routing('http://test.host/block/articles', { :controller => 'block_articles', :action => 'index' })
end
assert_routing('https://test.host/block/articles', { :controller => 'block_articles', :action => 'index' })
@@ -95,7 +107,7 @@ class RoutingAssertionsTest < ActionController::TestCase
end
assert_routing('/artikel', :controller => 'articles', :action => 'index')
- assert_raise(ActionController::RoutingError) do
+ assert_raise(Assertion) do
assert_routing('/articles', { :controller => 'articles', :action => 'index' })
end
end
diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb
index e8da790e50..4e83ad16d7 100644
--- a/actionpack/test/dispatch/routing_test.rb
+++ b/actionpack/test/dispatch/routing_test.rb
@@ -2,7 +2,6 @@
require 'erb'
require 'abstract_unit'
require 'controller/fake_controllers'
-require 'active_support/core_ext/object/inclusion'
class TestRoutingMapper < ActionDispatch::IntegrationTest
SprocketsApp = lambda { |env|
@@ -58,41 +57,46 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "remove", :action => :destroy, :as => :remove
end
- match 'account/logout' => redirect("/logout"), :as => :logout_redirect
- match 'account/login', :to => redirect("/login")
- match 'secure', :to => redirect("/secure/login")
+ get 'account/logout' => redirect("/logout"), :as => :logout_redirect
+ get 'account/login', :to => redirect("/login")
+ get 'secure', :to => redirect("/secure/login")
- match 'mobile', :to => redirect(:subdomain => 'mobile')
- match 'super_new_documentation', :to => redirect(:host => 'super-docs.com')
+ get 'mobile', :to => redirect(:subdomain => 'mobile')
+ get 'documentation', :to => redirect(:domain => 'example-documentation.com', :path => '')
+ get 'new_documentation', :to => redirect(:path => '/documentation/new')
+ get 'super_new_documentation', :to => redirect(:host => 'super-docs.com')
- match 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector)
+ get 'stores/:name', :to => redirect(:subdomain => 'stores', :path => '/%{name}')
+ get 'stores/:name(*rest)', :to => redirect(:subdomain => 'stores', :path => '/%{name}%{rest}')
+
+ get 'youtube_favorites/:youtube_id/:name', :to => redirect(YoutubeFavoritesRedirector)
constraints(lambda { |req| true }) do
- match 'account/overview'
+ get 'account/overview'
end
- match '/account/nested/overview'
- match 'sign_in' => "sessions#new"
+ get '/account/nested/overview'
+ get 'sign_in' => "sessions#new"
- match 'account/modulo/:name', :to => redirect("/%{name}s")
- match 'account/proc/:name', :to => redirect {|params, req| "/#{params[:name].pluralize}" }
- match 'account/proc_req' => redirect {|params, req| "/#{req.method}" }
+ get 'account/modulo/:name', :to => redirect("/%{name}s")
+ get 'account/proc/:name', :to => redirect {|params, req| "/#{params[:name].pluralize}" }
+ get 'account/proc_req' => redirect {|params, req| "/#{req.method}" }
- match 'account/google' => redirect('http://www.google.com/', :status => 302)
+ get 'account/google' => redirect('http://www.google.com/', :status => 302)
match 'openid/login', :via => [:get, :post], :to => "openid#login"
controller(:global) do
get 'global/hide_notice'
- match 'global/export', :to => :export, :as => :export_request
- match '/export/:id/:file', :to => :export, :as => :export_download, :constraints => { :file => /.*/ }
- match 'global/:action'
+ get 'global/export', :to => :export, :as => :export_request
+ get '/export/:id/:file', :to => :export, :as => :export_download, :constraints => { :file => /.*/ }
+ get 'global/:action'
end
- match "/local/:action", :controller => "local"
+ get "/local/:action", :controller => "local"
- match "/projects/status(.:format)"
- match "/404", :to => lambda { |env| [404, {"Content-Type" => "text/plain"}, ["NOT FOUND"]] }
+ get "/projects/status(.:format)"
+ get "/404", :to => lambda { |env| [404, {"Content-Type" => "text/plain"}, ["NOT FOUND"]] }
constraints(:ip => /192\.168\.1\.\d\d\d/) do
get 'admin' => "queenbee#index"
@@ -166,6 +170,8 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
post :preview, :on => :collection
end
end
+
+ post 'new', :action => 'new', :on => :collection, :as => :new
end
resources :replies do
@@ -277,25 +283,25 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- match 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
+ get 'sprockets.js' => ::TestRoutingMapper::SprocketsApp
- match 'people/:id/update', :to => 'people#update', :as => :update_person
- match '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person
+ get 'people/:id/update', :to => 'people#update', :as => :update_person
+ get '/projects/:project_id/people/:id/update', :to => 'people#update', :as => :update_project_person
# misc
- match 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article
+ get 'articles/:year/:month/:day/:title', :to => "articles#show", :as => :article
# default params
- match 'inline_pages/(:id)', :to => 'pages#show', :id => 'home'
- match 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' }
+ get 'inline_pages/(:id)', :to => 'pages#show', :id => 'home'
+ get 'default_pages/(:id)', :to => 'pages#show', :defaults => { :id => 'home' }
defaults :id => 'home' do
- match 'scoped_pages/(:id)', :to => 'pages#show'
+ get 'scoped_pages/(:id)', :to => 'pages#show'
end
namespace :account do
- match 'shorthand'
- match 'description', :to => :description, :as => "description"
- match ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback
+ get 'shorthand'
+ get 'description', :to => :description, :as => "description"
+ get ':action/callback', :action => /twitter|github/, :to => "callbacks", :as => :callback
resource :subscription, :credit, :credit_card
root :to => "account#index"
@@ -318,7 +324,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
controller :articles do
scope '/articles', :as => 'article' do
scope :path => '/:title', :title => /[a-z]+/, :as => :with_title do
- match '/:id', :to => :with_id, :as => ""
+ get '/:id', :to => :with_id, :as => ""
end
end
end
@@ -327,7 +333,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
resources :rooms
end
- match '/info' => 'projects#info', :as => 'info'
+ get '/info' => 'projects#info', :as => 'info'
namespace :admin do
scope '(:locale)', :locale => /en|pl/ do
@@ -357,11 +363,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
resources :errors, :shallow => true do
resources :notices
end
+ get 'api/version'
end
scope :path => 'api' do
resource :me
- match '/' => 'mes#index'
+ get '/' => 'mes#index'
end
get "(/:username)/followers" => "followers#index"
@@ -374,7 +381,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
end
end
- match "whatever/:controller(/:action(/:id))", :id => /\d+/
+ get "whatever/:controller(/:action(/:id))", :id => /\d+/
resource :profile do
get :settings
@@ -407,7 +414,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
namespace :private do
root :to => redirect('/private/index')
- match "index", :to => 'private#index'
+ get "index", :to => 'private#index'
end
scope :only => [:index, :show] do
@@ -475,6 +482,17 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get :preview, :on => :member
end
+ resources :profiles, :param => :username, :username => /[a-z]+/ do
+ get :details, :on => :member
+ resources :messages
+ end
+
+ resources :orders do
+ constraints :download => /[0-9a-f]{8}-(?:[0-9a-f]{4}-){3}[0-9a-f]{12}/ do
+ resources :downloads, :param => :download, :shallow => true
+ end
+ end
+
scope :as => "routes" do
get "/c/:id", :as => :collision, :to => "collision#show"
get "/collision", :to => "collision#show"
@@ -484,7 +502,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get "/forced_collision", :as => :forced_collision, :to => "forced_collision#show"
end
- match '/purchases/:token/:filename',
+ get '/purchases/:token/:filename',
:to => 'purchases#fetch',
:token => /[[:alnum:]]{10}/,
:filename => /(.+)/,
@@ -494,19 +512,19 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
resources :todos, :id => /\d+/
end
- scope '/countries/:country', :constraints => lambda { |params, req| params[:country].in?(["all", "France"]) } do
- match '/', :to => 'countries#index'
- match '/cities', :to => 'countries#cities'
+ scope '/countries/:country', :constraints => lambda { |params, req| %w(all France).include?(params[:country]) } do
+ get '/', :to => 'countries#index'
+ get '/cities', :to => 'countries#cities'
end
- match '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' }
+ get '/countries/:country/(*other)', :to => redirect{ |params, req| params[:other] ? "/countries/all/#{params[:other]}" : '/countries/all' }
- match '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
+ get '/:locale/*file.:format', :to => 'files#show', :file => /path\/to\/existing\/file/
scope '/italians' do
- match '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor
- match '/sculptors', :to => 'italians#sculptors'
- match '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/}
+ get '/writers', :to => 'italians#writers', :constraints => ::TestRoutingMapper::IpRestrictor
+ get '/sculptors', :to => 'italians#sculptors'
+ get '/painters/:painter', :to => 'italians#painters', :constraints => {:painter => /michelangelo/}
end
end
end
@@ -622,7 +640,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
self.class.stub_controllers do |routes|
routes.draw do
namespace :admin do
- match '/:controller(/:action(/:id(.:format)))'
+ get '/:controller(/:action(/:id(.:format)))'
end
end
end
@@ -688,11 +706,31 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
verify_redirect 'http://mobile.example.com/mobile'
end
+ def test_redirect_hash_with_domain_and_path
+ get '/documentation'
+ verify_redirect 'http://www.example-documentation.com'
+ end
+
+ def test_redirect_hash_with_path
+ get '/new_documentation'
+ verify_redirect 'http://www.example.com/documentation/new'
+ end
+
def test_redirect_hash_with_host
get '/super_new_documentation?section=top'
verify_redirect 'http://super-docs.com/super_new_documentation?section=top'
end
+ def test_redirect_hash_path_substitution
+ get '/stores/iernest'
+ verify_redirect 'http://stores.example.com/iernest'
+ end
+
+ def test_redirect_hash_path_substitution_with_catch_all
+ get '/stores/iernest/products'
+ verify_redirect 'http://stores.example.com/iernest/products'
+ end
+
def test_redirect_class
get '/youtube_favorites/oHg5SJYRHA0/rick-rolld'
verify_redirect 'http://www.youtube.com/watch?v=oHg5SJYRHA0'
@@ -797,6 +835,15 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal original_options, options
end
+ def test_url_for_does_not_modify_controller
+ controller = '/projects'
+ options = {:controller => controller, :action => 'status', :only_path => true}
+ url = url_for(options)
+
+ assert_equal '/projects/status', url
+ assert_equal '/projects', controller
+ end
+
# tests the arguments modification free version of define_hash_access
def test_named_route_with_no_side_effects
original_options = { :host => 'test.host' }
@@ -846,6 +893,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal '/projects/1/edit', edit_project_path(:id => '1')
end
+ def test_projects_with_post_action_and_new_path_on_collection
+ post '/projects/new'
+ assert_equal "project#new", @response.body
+ assert_equal "/projects/new", new_projects_path
+ end
+
def test_projects_involvements
get '/projects/1/involvements'
assert_equal 'involvements#index', @response.body
@@ -1026,6 +1079,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'pasts#destroy', @response.body
assert_equal '/past', past_path
+ patch '/present'
+ assert_equal 'presents#update', @response.body
+ assert_equal '/present', present_path
+
put '/present'
assert_equal 'presents#update', @response.body
assert_equal '/present', present_path
@@ -1044,6 +1101,10 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'relationships#destroy', @response.body
assert_equal '/relationships/1', relationship_path(1)
+ patch '/friendships/1'
+ assert_equal 'friendships#update', @response.body
+ assert_equal '/friendships/1', friendship_path(1)
+
put '/friendships/1'
assert_equal 'friendships#update', @response.body
assert_equal '/friendships/1', friendship_path(1)
@@ -1220,6 +1281,12 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal 'account#shorthand', @response.body
end
+ def test_match_shorthand_with_module
+ assert_equal '/api/version', api_version_path
+ get '/api/version'
+ assert_equal 'api/api#version', @response.body
+ end
+
def test_dynamically_generated_helpers_on_collection_do_not_clobber_resources_url_helper
assert_equal '/replies', replies_path
end
@@ -1739,7 +1806,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/movies/00001'
assert_equal 'Not Found', @response.body
- assert_raises(ActionController::RoutingError){ movie_path(:id => '00001') }
+ assert_raises(ActionController::UrlGenerationError){ movie_path(:id => '00001') }
get '/movies/0001/reviews'
assert_equal 'reviews#index', @response.body
@@ -1747,7 +1814,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/movies/00001/reviews'
assert_equal 'Not Found', @response.body
- assert_raises(ActionController::RoutingError){ movie_reviews_path(:movie_id => '00001') }
+ assert_raises(ActionController::UrlGenerationError){ movie_reviews_path(:movie_id => '00001') }
get '/movies/0001/reviews/0001'
assert_equal 'reviews#show', @response.body
@@ -1755,7 +1822,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/movies/00001/reviews/0001'
assert_equal 'Not Found', @response.body
- assert_raises(ActionController::RoutingError){ movie_path(:movie_id => '00001', :id => '00001') }
+ assert_raises(ActionController::UrlGenerationError){ movie_path(:movie_id => '00001', :id => '00001') }
get '/movies/0001/trailer'
assert_equal 'trailers#show', @response.body
@@ -1763,7 +1830,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/movies/00001/trailer'
assert_equal 'Not Found', @response.body
- assert_raises(ActionController::RoutingError){ movie_trailer_path(:movie_id => '00001') }
+ assert_raises(ActionController::UrlGenerationError){ movie_trailer_path(:movie_id => '00001') }
end
def test_only_should_be_read_from_scope
@@ -2082,7 +2149,7 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
get '/lists/2/todos/1'
assert_equal 'Not Found', @response.body
- assert_raises(ActionController::RoutingError){ list_todo_path(:list_id => '2', :id => '1') }
+ assert_raises(ActionController::UrlGenerationError){ list_todo_path(:list_id => '2', :id => '1') }
end
def test_named_routes_collision_is_avoided_unless_explicitly_given_as
@@ -2175,6 +2242,36 @@ class TestRoutingMapper < ActionDispatch::IntegrationTest
assert_equal "/posts/1/admin", post_admin_root_path(:post_id => '1')
end
+ def test_custom_param
+ get '/profiles/bob'
+ assert_equal 'profiles#show', @response.body
+ assert_equal 'bob', @request.params[:username]
+
+ get '/profiles/bob/details'
+ assert_equal 'bob', @request.params[:username]
+
+ get '/profiles/bob/messages/34'
+ assert_equal 'bob', @request.params[:profile_username]
+ assert_equal '34', @request.params[:id]
+ end
+
+ def test_custom_param_constraint
+ get '/profiles/bob1'
+ assert_equal 404, @response.status
+
+ get '/profiles/bob1/details'
+ assert_equal 404, @response.status
+
+ get '/profiles/bob1/messages/34'
+ assert_equal 404, @response.status
+ end
+
+ def test_shallow_custom_param
+ get '/downloads/0c0c0b68-d24b-11e1-a861-001ff3fffe6f.zip'
+ assert_equal 'downloads#show', @response.body
+ assert_equal '0c0c0b68-d24b-11e1-a861-001ff3fffe6f', @request.params[:download]
+ end
+
private
def with_https
old_https = https?
@@ -2205,12 +2302,12 @@ class TestAppendingRoutes < ActionDispatch::IntegrationTest
s = self
@app = ActionDispatch::Routing::RouteSet.new
@app.append do
- match '/hello' => s.simple_app('fail')
- match '/goodbye' => s.simple_app('goodbye')
+ get '/hello' => s.simple_app('fail')
+ get '/goodbye' => s.simple_app('goodbye')
end
@app.draw do
- match '/hello' => s.simple_app('hello')
+ get '/hello' => s.simple_app('hello')
end
end
@@ -2318,12 +2415,12 @@ end
class TestUriPathEscaping < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
app.draw do
- match '/:segment' => lambda { |env|
+ get '/:segment' => lambda { |env|
path_params = env['action_dispatch.request.path_parameters']
[200, { 'Content-Type' => 'text/plain' }, [path_params[:segment]]]
}, :as => :segment
- match '/*splat' => lambda { |env|
+ get '/*splat' => lambda { |env|
path_params = env['action_dispatch.request.path_parameters']
[200, { 'Content-Type' => 'text/plain' }, [path_params[:splat]]]
}, :as => :splat
@@ -2355,7 +2452,7 @@ end
class TestUnicodePaths < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
app.draw do
- match "/#{Rack::Utils.escape("ほげ")}" => lambda { |env|
+ get "/ほげ" => lambda { |env|
[200, { 'Content-Type' => 'text/plain' }, []]
}, :as => :unicode_path
end
@@ -2385,10 +2482,10 @@ class TestMultipleNestedController < ActionDispatch::IntegrationTest
app.draw do
namespace :foo do
namespace :bar do
- match "baz" => "baz#index"
+ get "baz" => "baz#index"
end
end
- match "pooh" => "pooh#index"
+ get "pooh" => "pooh#index"
end
end
@@ -2399,18 +2496,15 @@ class TestMultipleNestedController < ActionDispatch::IntegrationTest
get "/foo/bar/baz"
assert_equal "/pooh", @response.body
end
-
end
class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
app.draw do
- match "/~user" => lambda { |env|
- [200, { 'Content-Type' => 'text/plain' }, []]
- }, :as => :tilde_path
- match "/young-and-fine" => lambda { |env|
- [200, { 'Content-Type' => 'text/plain' }, []]
- }, :as => :tilde_path
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+
+ get "/~user" => ok
+ get "/young-and-fine" => ok
end
end
@@ -2428,3 +2522,216 @@ class TestTildeAndMinusPaths < ActionDispatch::IntegrationTest
end
end
+
+class TestRedirectInterpolation < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+
+ get "/foo/:id" => redirect("/foo/bar/%{id}")
+ get "/bar/:id" => redirect(:path => "/foo/bar/%{id}")
+ get "/foo/bar/:id" => ok
+ end
+ end
+
+ def app; Routes end
+
+ test "redirect escapes interpolated parameters with redirect proc" do
+ get "/foo/1%3E"
+ verify_redirect "http://www.example.com/foo/bar/1%3E"
+ end
+
+ test "redirect escapes interpolated parameters with option proc" do
+ get "/bar/1%3E"
+ verify_redirect "http://www.example.com/foo/bar/1%3E"
+ end
+
+private
+ def verify_redirect(url, status=301)
+ assert_equal status, @response.status
+ assert_equal url, @response.headers['Location']
+ assert_equal expected_redirect_body(url), @response.body
+ end
+
+ def expected_redirect_body(url)
+ %(<html><body>You are being <a href="#{ERB::Util.h(url)}">redirected</a>.</body></html>)
+ end
+end
+
+class TestConstraintsAccessingParameters < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+
+ get "/:foo" => ok, :constraints => lambda { |r| r.params[:foo] == 'foo' }
+ get "/:bar" => ok
+ end
+ end
+
+ def app; Routes end
+
+ test "parameters are reset between constraint checks" do
+ get "/bar"
+ assert_equal nil, @request.params[:foo]
+ assert_equal "bar", @request.params[:bar]
+ end
+end
+
+class TestOptimizedNamedRoutes < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+ get '/foo' => ok, as: :foo
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ test 'enabled when not mounted and default_url_options is empty' do
+ assert Routes.url_helpers.optimize_routes_generation?
+ end
+
+ test 'named route called as singleton method' do
+ assert_equal '/foo', Routes.url_helpers.foo_path
+ end
+
+ test 'named route called on included module' do
+ assert_equal '/foo', foo_path
+ end
+end
+
+class TestNamedRouteUrlHelpers < ActionDispatch::IntegrationTest
+ class CategoriesController < ActionController::Base
+ def show
+ render :text => "categories#show"
+ end
+ end
+
+ class ProductsController < ActionController::Base
+ def show
+ render :text => "products#show"
+ end
+ end
+
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ scope :module => "test_named_route_url_helpers" do
+ get "/categories/:id" => 'categories#show', :as => :category
+ get "/products/:id" => 'products#show', :as => :product
+ end
+ end
+ end
+
+ def app; Routes end
+
+ include Routes.url_helpers
+
+ test "url helpers do not ignore nil parameters when using non-optimized routes" do
+ Routes.stubs(:optimize_routes_generation?).returns(false)
+
+ get "/categories/1"
+ assert_response :success
+ assert_raises(ActionController::UrlGenerationError) { product_path(nil) }
+ end
+end
+
+class TestUrlConstraints < ActionDispatch::IntegrationTest
+ Routes = ActionDispatch::Routing::RouteSet.new.tap do |app|
+ app.draw do
+ ok = lambda { |env| [200, { 'Content-Type' => 'text/plain' }, []] }
+
+ constraints :subdomain => 'admin' do
+ get '/' => ok, :as => :admin_root
+ end
+
+ scope :constraints => { :protocol => 'https://' } do
+ get '/' => ok, :as => :secure_root
+ end
+
+ get '/' => ok, :as => :alternate_root, :constraints => { :port => 8080 }
+ end
+ end
+
+ include Routes.url_helpers
+ def app; Routes end
+
+ test "constraints are copied to defaults when using constraints method" do
+ assert_equal 'http://admin.example.com/', admin_root_url
+
+ get 'http://admin.example.com/'
+ assert_response :success
+ end
+
+ test "constraints are copied to defaults when using scope constraints hash" do
+ assert_equal 'https://www.example.com/', secure_root_url
+
+ get 'https://www.example.com/'
+ assert_response :success
+ end
+
+ test "constraints are copied to defaults when using route constraints hash" do
+ assert_equal 'http://www.example.com:8080/', alternate_root_url
+
+ get 'http://www.example.com:8080/'
+ assert_response :success
+ end
+end
+
+class TestInvalidUrls < ActionDispatch::IntegrationTest
+ class FooController < ActionController::Base
+ def show
+ render :text => "foo#show"
+ end
+ end
+
+ test "invalid UTF-8 encoding returns a 400 Bad Request" do
+ with_routing do |set|
+ set.draw do
+ get "/bar/:id", :to => redirect("/foo/show/%{id}")
+ get "/foo/show(/:id)", :to => "test_invalid_urls/foo#show"
+ get "/foo(/:action(/:id))", :to => "test_invalid_urls/foo"
+ get "/:controller(/:action(/:id))"
+ end
+
+ get "/%E2%EF%BF%BD%A6"
+ assert_response :bad_request
+
+ get "/foo/%E2%EF%BF%BD%A6"
+ assert_response :bad_request
+
+ get "/foo/show/%E2%EF%BF%BD%A6"
+ assert_response :bad_request
+
+ get "/bar/%E2%EF%BF%BD%A6"
+ assert_response :bad_request
+ end
+ end
+end
+
+class TestOptionalRootSegments < ActionDispatch::IntegrationTest
+ stub_controllers do |routes|
+ Routes = routes
+ Routes.draw do
+ get '/(page/:page)', :to => 'pages#index', :as => :root
+ end
+ end
+
+ def app
+ Routes
+ end
+
+ include Routes.url_helpers
+
+ def test_optional_root_segments
+ get '/'
+ assert_equal 'pages#index', @response.body
+ assert_equal '/', root_path
+
+ get '/page/1'
+ assert_equal 'pages#index', @response.body
+ assert_equal '1', @request.params[:page]
+ assert_equal '/page/1', root_path('1')
+ assert_equal '/page/1', root_path(:page => '1')
+ end
+end
diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb
new file mode 100644
index 0000000000..8daf3d3f5e
--- /dev/null
+++ b/actionpack/test/dispatch/session/abstract_store_test.rb
@@ -0,0 +1,56 @@
+require 'abstract_unit'
+require 'action_dispatch/middleware/session/abstract_store'
+
+module ActionDispatch
+ module Session
+ class AbstractStoreTest < ActiveSupport::TestCase
+ class MemoryStore < AbstractStore
+ def initialize(app)
+ @sessions = {}
+ super
+ end
+
+ def get_session(env, sid)
+ sid ||= 1
+ session = @sessions[sid] ||= {}
+ [sid, session]
+ end
+
+ def set_session(env, sid, session, options)
+ @sessions[sid] = session
+ end
+ end
+
+ def test_session_is_set
+ env = {}
+ as = MemoryStore.new app
+ as.call(env)
+
+ assert @env
+ assert Request::Session.find @env
+ end
+
+ def test_new_session_object_is_merged_with_old
+ env = {}
+ as = MemoryStore.new app
+ as.call(env)
+
+ assert @env
+ session = Request::Session.find @env
+ session['foo'] = 'bar'
+
+ as.call(@env)
+ session1 = Request::Session.find @env
+
+ refute_equal session, session1
+ assert_equal session.to_hash, session1.to_hash
+ end
+
+ private
+ def app(&block)
+ @env = nil
+ lambda { |env| @env = env }
+ end
+ end
+ end
+end
diff --git a/actionpack/test/dispatch/session/cache_store_test.rb b/actionpack/test/dispatch/session/cache_store_test.rb
index 12405bf45d..a74e165826 100644
--- a/actionpack/test/dispatch/session/cache_store_test.rb
+++ b/actionpack/test/dispatch/session/cache_store_test.rb
@@ -164,7 +164,7 @@ class CacheStoreTest < ActionDispatch::IntegrationTest
def with_test_route_set
with_routing do |set|
set.draw do
- match ':action', :to => ::CacheStoreTest::TestController
+ get ':action', :to => ::CacheStoreTest::TestController
end
@app = self.class.build_app(set) do |middleware|
diff --git a/actionpack/test/dispatch/session/cookie_store_test.rb b/actionpack/test/dispatch/session/cookie_store_test.rb
index 19969394cd..41fa036a92 100644
--- a/actionpack/test/dispatch/session/cookie_store_test.rb
+++ b/actionpack/test/dispatch/session/cookie_store_test.rb
@@ -30,6 +30,11 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
render :text => "id: #{request.session_options[:id]}"
end
+ def get_class_after_reset_session
+ reset_session
+ render :text => "class: #{session.class}"
+ end
+
def call_session_clear
session.clear
head :ok
@@ -187,6 +192,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
get '/call_reset_session'
assert_response :success
assert_not_equal [], headers['Set-Cookie']
+ assert_not_nil session_payload
assert_not_equal session_payload, cookies[SessionKey]
get '/get_session_value'
@@ -195,6 +201,20 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
end
end
+ def test_class_type_after_session_reset
+ with_test_route_set do
+ get '/set_session_value'
+ assert_response :success
+ assert_equal "_myapp_session=#{response.body}; path=/; HttpOnly",
+ headers['Set-Cookie']
+
+ get '/get_class_after_reset_session'
+ assert_response :success
+ assert_not_equal [], headers['Set-Cookie']
+ assert_equal 'class: ActionDispatch::Request::Session', response.body
+ end
+ end
+
def test_getting_from_nonexistent_session
with_test_route_set do
get '/get_session_value'
@@ -317,7 +337,7 @@ class CookieStoreTest < ActionDispatch::IntegrationTest
def with_test_route_set(options = {})
with_routing do |set|
set.draw do
- match ':action', :to => ::CookieStoreTest::TestController
+ get ':action', :to => ::CookieStoreTest::TestController
end
options = { :key => SessionKey }.merge!(options)
diff --git a/actionpack/test/dispatch/session/mem_cache_store_test.rb b/actionpack/test/dispatch/session/mem_cache_store_test.rb
index 5277c92b55..e53ce4195b 100644
--- a/actionpack/test/dispatch/session/mem_cache_store_test.rb
+++ b/actionpack/test/dispatch/session/mem_cache_store_test.rb
@@ -34,9 +34,9 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
end
begin
- require 'memcache'
- memcache = MemCache.new('localhost:11211')
- memcache.set('ping', '')
+ require 'dalli'
+ ss = Dalli::Client.new('localhost:11211').stats
+ raise Dalli::DalliError unless ss['localhost:11211']
def test_setting_and_getting_session_value
with_test_route_set do
@@ -131,11 +131,6 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
get '/get_session_id'
assert_response :success
end
- with_autoload_path "session_autoload_test" do
- get '/get_session_value'
- assert_response :success
- assert_equal 'foo: #<SessionAutoloadTest::Foo bar:"baz">', response.body, "should auto-load unloaded class"
- end
end
end
@@ -165,7 +160,7 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
assert_not_equal session_id, cookies['_session_id']
end
end
- rescue LoadError, RuntimeError
+ rescue LoadError, RuntimeError, Dalli::DalliError
$stderr.puts "Skipping MemCacheStoreTest tests. Start memcached and try again."
end
@@ -173,7 +168,7 @@ class MemCacheStoreTest < ActionDispatch::IntegrationTest
def with_test_route_set
with_routing do |set|
set.draw do
- match ':action', :to => ::MemCacheStoreTest::TestController
+ get ':action', :to => ::MemCacheStoreTest::TestController
end
@app = self.class.build_app(set) do |middleware|
diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb
new file mode 100644
index 0000000000..6f075a9074
--- /dev/null
+++ b/actionpack/test/dispatch/ssl_test.rb
@@ -0,0 +1,157 @@
+require 'abstract_unit'
+
+class SSLTest < ActionDispatch::IntegrationTest
+ def default_app
+ lambda { |env|
+ headers = {'Content-Type' => "text/html"}
+ headers['Set-Cookie'] = "id=1; path=/\ntoken=abc; path=/; secure; HttpOnly"
+ [200, headers, ["OK"]]
+ }
+ end
+
+ def app
+ @app ||= ActionDispatch::SSL.new(default_app)
+ end
+ attr_writer :app
+
+ def test_allows_https_url
+ get "https://example.org/path?key=value"
+ assert_response :success
+ end
+
+ def test_allows_https_proxy_header_url
+ get "http://example.org/", {}, 'HTTP_X_FORWARDED_PROTO' => "https"
+ assert_response :success
+ end
+
+ def test_redirects_http_to_https
+ get "http://example.org/path?key=value"
+ assert_response :redirect
+ assert_equal "https://example.org/path?key=value",
+ response.headers['Location']
+ end
+
+ def test_hsts_header_by_default
+ get "https://example.org/"
+ assert_equal "max-age=31536000",
+ response.headers['Strict-Transport-Security']
+ end
+
+ def test_hsts_header
+ self.app = ActionDispatch::SSL.new(default_app, :hsts => true)
+ get "https://example.org/"
+ assert_equal "max-age=31536000",
+ response.headers['Strict-Transport-Security']
+ end
+
+ def test_disable_hsts_header
+ self.app = ActionDispatch::SSL.new(default_app, :hsts => false)
+ get "https://example.org/"
+ refute response.headers['Strict-Transport-Security']
+ end
+
+ def test_hsts_expires
+ self.app = ActionDispatch::SSL.new(default_app, :hsts => { :expires => 500 })
+ get "https://example.org/"
+ assert_equal "max-age=500",
+ response.headers['Strict-Transport-Security']
+ end
+
+ def test_hsts_include_subdomains
+ self.app = ActionDispatch::SSL.new(default_app, :hsts => { :subdomains => true })
+ get "https://example.org/"
+ assert_equal "max-age=31536000; includeSubDomains",
+ response.headers['Strict-Transport-Security']
+ end
+
+ def test_flag_cookies_as_secure
+ get "https://example.org/"
+ assert_equal ["id=1; path=/; secure", "token=abc; path=/; secure; HttpOnly" ],
+ response.headers['Set-Cookie'].split("\n")
+ end
+
+ def test_flag_cookies_as_secure_at_end_of_line
+ self.app = ActionDispatch::SSL.new(lambda { |env|
+ headers = {
+ 'Content-Type' => "text/html",
+ 'Set-Cookie' => "problem=def; path=/; HttpOnly; secure"
+ }
+ [200, headers, ["OK"]]
+ })
+
+ get "https://example.org/"
+ assert_equal ["problem=def; path=/; HttpOnly; secure"],
+ response.headers['Set-Cookie'].split("\n")
+ end
+
+ def test_flag_cookies_as_secure_with_more_spaces_before
+ self.app = ActionDispatch::SSL.new(lambda { |env|
+ headers = {
+ 'Content-Type' => "text/html",
+ 'Set-Cookie' => "problem=def; path=/; HttpOnly; secure"
+ }
+ [200, headers, ["OK"]]
+ })
+
+ get "https://example.org/"
+ assert_equal ["problem=def; path=/; HttpOnly; secure"],
+ response.headers['Set-Cookie'].split("\n")
+ end
+
+ def test_flag_cookies_as_secure_with_more_spaces_after
+ self.app = ActionDispatch::SSL.new(lambda { |env|
+ headers = {
+ 'Content-Type' => "text/html",
+ 'Set-Cookie' => "problem=def; path=/; secure; HttpOnly"
+ }
+ [200, headers, ["OK"]]
+ })
+
+ get "https://example.org/"
+ assert_equal ["problem=def; path=/; secure; HttpOnly"],
+ response.headers['Set-Cookie'].split("\n")
+ end
+
+ def test_no_cookies
+ self.app = ActionDispatch::SSL.new(lambda { |env|
+ [200, {'Content-Type' => "text/html"}, ["OK"]]
+ })
+ get "https://example.org/"
+ assert !response.headers['Set-Cookie']
+ end
+
+ def test_redirect_to_host
+ self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org")
+ get "http://example.org/path?key=value"
+ assert_equal "https://ssl.example.org/path?key=value",
+ response.headers['Location']
+ end
+
+ def test_redirect_to_port
+ self.app = ActionDispatch::SSL.new(default_app, :port => 8443)
+ get "http://example.org/path?key=value"
+ assert_equal "https://example.org:8443/path?key=value",
+ response.headers['Location']
+ end
+
+ def test_redirect_to_host_and_port
+ self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org", :port => 8443)
+ get "http://example.org/path?key=value"
+ assert_equal "https://ssl.example.org:8443/path?key=value",
+ response.headers['Location']
+ end
+
+ def test_redirect_to_secure_host_when_on_subdomain
+ self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org")
+ get "http://ssl.example.org/path?key=value"
+ assert_equal "https://ssl.example.org/path?key=value",
+ response.headers['Location']
+ end
+
+ def test_redirect_to_secure_subdomain_when_on_deep_subdomain
+ self.app = ActionDispatch::SSL.new(default_app, :host => "example.co.uk")
+ get "http://double.rainbow.what.does.it.mean.example.co.uk/path?key=value"
+ assert_equal "https://example.co.uk/path?key=value",
+ response.headers['Location']
+ end
+end
diff --git a/actionpack/test/dispatch/static_test.rb b/actionpack/test/dispatch/static_test.rb
index 092ca3e20a..112f470786 100644
--- a/actionpack/test/dispatch/static_test.rb
+++ b/actionpack/test/dispatch/static_test.rb
@@ -7,6 +7,10 @@ module StaticTests
assert_equal "Hello, World!", get("/nofile").body
end
+ def test_handles_urls_with_bad_encoding
+ assert_equal "Hello, World!", get("/doorkeeper%E3E4").body
+ end
+
def test_sets_cache_control
response = get("/index.html")
assert_html "/index.html", response
diff --git a/actionpack/test/dispatch/test_request_test.rb b/actionpack/test/dispatch/test_request_test.rb
index 4ee1d61146..6047631ba3 100644
--- a/actionpack/test/dispatch/test_request_test.rb
+++ b/actionpack/test/dispatch/test_request_test.rb
@@ -55,6 +55,13 @@ class TestRequestTest < ActiveSupport::TestCase
assert_cookies({"user_name" => "david"}, req.cookie_jar)
end
+ test "does not complain when Rails.application is nil" do
+ Rails.stubs(:application).returns(nil)
+ req = ActionDispatch::TestRequest.new
+
+ assert_equal false, req.env.empty?
+ end
+
private
def assert_cookies(expected, cookie_jar)
assert_equal(expected, cookie_jar.instance_variable_get("@cookies"))
diff --git a/actionpack/test/dispatch/uploaded_file_test.rb b/actionpack/test/dispatch/uploaded_file_test.rb
index 0b95291e18..e69c1fbed4 100644
--- a/actionpack/test/dispatch/uploaded_file_test.rb
+++ b/actionpack/test/dispatch/uploaded_file_test.rb
@@ -12,7 +12,7 @@ module ActionDispatch
uf = Http::UploadedFile.new(:filename => 'foo', :tempfile => Object.new)
assert_equal 'foo', uf.original_filename
end
-
+
def test_filename_should_be_in_utf_8
uf = Http::UploadedFile.new(:filename => 'foo', :tempfile => Object.new)
assert_equal "UTF-8", uf.original_filename.encoding.to_s
@@ -65,6 +65,12 @@ module ActionDispatch
end
end
+ def test_delegate_eof_to_tempfile
+ tf = Class.new { def eof?; true end; }
+ uf = Http::UploadedFile.new(:tempfile => tf.new)
+ assert uf.eof?
+ end
+
def test_respond_to?
tf = Class.new { def read; yield end }
uf = Http::UploadedFile.new(:tempfile => tf.new)
diff --git a/actionpack/test/dispatch/url_generation_test.rb b/actionpack/test/dispatch/url_generation_test.rb
index 2b54bc62b0..e56e8ddc57 100644
--- a/actionpack/test/dispatch/url_generation_test.rb
+++ b/actionpack/test/dispatch/url_generation_test.rb
@@ -3,7 +3,7 @@ require 'abstract_unit'
module TestUrlGeneration
class WithMountPoint < ActionDispatch::IntegrationTest
Routes = ActionDispatch::Routing::RouteSet.new
- Routes.draw { match "/foo", :to => "my_route_generating#index", :as => :foo }
+ include Routes.url_helpers
class ::MyRouteGeneratingController < ActionController::Base
include Routes.url_helpers
@@ -12,7 +12,11 @@ module TestUrlGeneration
end
end
- include Routes.url_helpers
+ Routes.draw do
+ get "/foo", :to => "my_route_generating#index", :as => :foo
+
+ mount MyRouteGeneratingController.action(:index), at: '/bar'
+ end
def _routes
Routes
@@ -30,11 +34,16 @@ module TestUrlGeneration
assert_equal "/bar/foo", foo_path(:script_name => "/bar")
end
- test "the request's SCRIPT_NAME takes precedence over the routes'" do
+ test "the request's SCRIPT_NAME takes precedence over the route" do
get "/foo", {}, 'SCRIPT_NAME' => "/new", 'action_dispatch.routes' => Routes
assert_equal "/new/foo", response.body
end
+ test "the request's SCRIPT_NAME wraps the mounted app's" do
+ get '/new/bar/foo', {}, 'SCRIPT_NAME' => '/new', 'PATH_INFO' => '/bar/foo', 'action_dispatch.routes' => Routes
+ assert_equal "/new/bar/foo", response.body
+ end
+
test "handling http protocol with https set" do
https!
assert_equal "http://www.example.com/foo", foo_url(:protocol => "http")