diff options
Diffstat (limited to 'actionpack/test')
30 files changed, 617 insertions, 480 deletions
diff --git a/actionpack/test/abstract/collector_test.rb b/actionpack/test/abstract/collector_test.rb index fc59bf19c4..3b36e43c0b 100644 --- a/actionpack/test/abstract/collector_test.rb +++ b/actionpack/test/abstract/collector_test.rb @@ -53,9 +53,9 @@ module AbstractController collector.html collector.text(:foo) collector.js(:bar) { :baz } - assert_equal [Mime::HTML, [], nil], collector.responses[0] - assert_equal [Mime::TEXT, [:foo], nil], collector.responses[1] - assert_equal [Mime::JS, [:bar]], collector.responses[2][0,2] + assert_equal [Mime::Type[:HTML], [], nil], collector.responses[0] + assert_equal [Mime::Type[:TEXT], [:foo], nil], collector.responses[1] + assert_equal [Mime::Type[:JS], [:bar]], collector.responses[2][0,2] assert_equal :baz, collector.responses[2][2].call end end diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb index 1954324222..ef7aab72c6 100644 --- a/actionpack/test/abstract_unit.rb +++ b/actionpack/test/abstract_unit.rb @@ -104,7 +104,6 @@ class ActionDispatch::IntegrationTest < ActiveSupport::TestCase middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public") middleware.use ActionDispatch::DebugExceptions middleware.use ActionDispatch::Callbacks - middleware.use ActionDispatch::ParamsParser middleware.use ActionDispatch::Cookies middleware.use ActionDispatch::Flash middleware.use Rack::Head @@ -406,7 +405,6 @@ def jruby_skip(message = '') skip message if defined?(JRUBY_VERSION) end -require 'mocha/setup' # FIXME: stop using mocha require 'active_support/testing/method_call_assertions' class ForkingExecutor diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb index beeafc2e53..7dfeadceb0 100644 --- a/actionpack/test/controller/action_pack_assertions_test.rb +++ b/actionpack/test/controller/action_pack_assertions_test.rb @@ -65,7 +65,7 @@ class ActionPackAssertionsController < ActionController::Base end def render_text_with_custom_content_type - render body: "Hello!", content_type: Mime::RSS + render body: "Hello!", content_type: Mime::Type[:RSS] end def session_stuffing diff --git a/actionpack/test/controller/caching_test.rb b/actionpack/test/controller/caching_test.rb index 5698159eba..bc0ffd3eaa 100644 --- a/actionpack/test/controller/caching_test.rb +++ b/actionpack/test/controller/caching_test.rb @@ -299,30 +299,42 @@ class CacheHelperOutputBufferTest < ActionController::TestCase def test_output_buffer output_buffer = ActionView::OutputBuffer.new controller = MockController.new - cache_helper = Object.new + cache_helper = Class.new do + def self.controller; end; + def self.output_buffer; end; + def self.output_buffer=; end; + end cache_helper.extend(ActionView::Helpers::CacheHelper) - cache_helper.expects(:controller).returns(controller).at_least(0) - cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0) - # if the output_buffer is changed, the new one should be html_safe and of the same type - cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0) - assert_nothing_raised do - cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + cache_helper.stub :controller, controller do + cache_helper.stub :output_buffer, output_buffer do + assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do + assert_nothing_raised do + cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + end + end + end end end def test_safe_buffer output_buffer = ActiveSupport::SafeBuffer.new controller = MockController.new - cache_helper = Object.new + cache_helper = Class.new do + def self.controller; end; + def self.output_buffer; end; + def self.output_buffer=; end; + end cache_helper.extend(ActionView::Helpers::CacheHelper) - cache_helper.expects(:controller).returns(controller).at_least(0) - cache_helper.expects(:output_buffer).returns(output_buffer).at_least(0) - # if the output_buffer is changed, the new one should be html_safe and of the same type - cache_helper.expects(:output_buffer=).with(responds_with(:html_safe?, true)).with(instance_of(output_buffer.class)).at_least(0) - assert_nothing_raised do - cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + cache_helper.stub :controller, controller do + cache_helper.stub :output_buffer, output_buffer do + assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do + assert_nothing_raised do + cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil } + end + end + end end end end diff --git a/actionpack/test/controller/content_type_test.rb b/actionpack/test/controller/content_type_test.rb index c5bbc479c9..4a86f1bad3 100644 --- a/actionpack/test/controller/content_type_test.rb +++ b/actionpack/test/controller/content_type_test.rb @@ -3,7 +3,7 @@ require 'abstract_unit' class OldContentTypeController < ActionController::Base # :ported: def render_content_type_from_body - response.content_type = Mime::RSS + response.content_type = Mime::Type[:RSS] render body: "hello world!" end @@ -14,7 +14,7 @@ class OldContentTypeController < ActionController::Base # :ported: def render_content_type_from_render - render body: "hello world!", :content_type => Mime::RSS + render body: "hello world!", :content_type => Mime::Type[:RSS] end # :ported: @@ -36,7 +36,7 @@ class OldContentTypeController < ActionController::Base end def render_change_for_builder - response.content_type = Mime::HTML + response.content_type = Mime::Type[:HTML] render :action => "render_default_for_builder" end @@ -45,7 +45,7 @@ class OldContentTypeController < ActionController::Base format.html { render body: "hello world!" } format.xml { render action: "render_default_content_types_for_respond_to" } format.js { render body: "hello world!" } - format.rss { render body: "hello world!", content_type: Mime::XML } + format.rss { render body: "hello world!", content_type: Mime::Type[:XML] } end end end @@ -64,68 +64,68 @@ class ContentTypeTest < ActionController::TestCase def test_render_defaults get :render_defaults assert_equal "utf-8", @response.charset - assert_equal Mime::TEXT, @response.content_type + assert_equal Mime::Type[:TEXT], @response.content_type end def test_render_changed_charset_default with_default_charset "utf-16" do get :render_defaults assert_equal "utf-16", @response.charset - assert_equal Mime::TEXT, @response.content_type + assert_equal Mime::Type[:TEXT], @response.content_type end end # :ported: def test_content_type_from_body get :render_content_type_from_body - assert_equal Mime::RSS, @response.content_type + assert_equal Mime::Type[:RSS], @response.content_type assert_equal "utf-8", @response.charset end # :ported: def test_content_type_from_render get :render_content_type_from_render - assert_equal Mime::RSS, @response.content_type + assert_equal Mime::Type[:RSS], @response.content_type assert_equal "utf-8", @response.charset end # :ported: def test_charset_from_body get :render_charset_from_body - assert_equal Mime::TEXT, @response.content_type + assert_equal Mime::Type[:TEXT], @response.content_type assert_equal "utf-16", @response.charset end # :ported: def test_nil_charset_from_body get :render_nil_charset_from_body - assert_equal Mime::TEXT, @response.content_type + assert_equal Mime::Type[:TEXT], @response.content_type assert_equal "utf-8", @response.charset, @response.headers.inspect end def test_nil_default_for_erb with_default_charset nil do get :render_default_for_erb - assert_equal Mime::HTML, @response.content_type + assert_equal Mime::Type[:HTML], @response.content_type assert_nil @response.charset, @response.headers.inspect end end def test_default_for_erb get :render_default_for_erb - assert_equal Mime::HTML, @response.content_type + assert_equal Mime::Type[:HTML], @response.content_type assert_equal "utf-8", @response.charset end def test_default_for_builder get :render_default_for_builder - assert_equal Mime::XML, @response.content_type + assert_equal Mime::Type[:XML], @response.content_type assert_equal "utf-8", @response.charset end def test_change_for_builder get :render_change_for_builder - assert_equal Mime::HTML, @response.content_type + assert_equal Mime::Type[:HTML], @response.content_type assert_equal "utf-8", @response.charset end @@ -144,24 +144,24 @@ class AcceptBasedContentTypeTest < ActionController::TestCase tests OldContentTypeController def test_render_default_content_types_for_respond_to - @request.accept = Mime::HTML.to_s + @request.accept = Mime::Type[:HTML].to_s get :render_default_content_types_for_respond_to - assert_equal Mime::HTML, @response.content_type + assert_equal Mime::Type[:HTML], @response.content_type - @request.accept = Mime::JS.to_s + @request.accept = Mime::Type[:JS].to_s get :render_default_content_types_for_respond_to - assert_equal Mime::JS, @response.content_type + assert_equal Mime::Type[:JS], @response.content_type end def test_render_default_content_types_for_respond_to_with_template - @request.accept = Mime::XML.to_s + @request.accept = Mime::Type[:XML].to_s get :render_default_content_types_for_respond_to - assert_equal Mime::XML, @response.content_type + assert_equal Mime::Type[:XML], @response.content_type end def test_render_default_content_types_for_respond_to_with_overwrite - @request.accept = Mime::RSS.to_s + @request.accept = Mime::Type[:RSS].to_s get :render_default_content_types_for_respond_to - assert_equal Mime::XML, @response.content_type + assert_equal Mime::Type[:XML], @response.content_type end end diff --git a/actionpack/test/controller/live_stream_test.rb b/actionpack/test/controller/live_stream_test.rb index e9c19b7acf..4d1c23cbee 100644 --- a/actionpack/test/controller/live_stream_test.rb +++ b/actionpack/test/controller/live_stream_test.rb @@ -112,7 +112,7 @@ module ActionController class TestController < ActionController::Base include ActionController::Live - attr_accessor :latch, :tc + attr_accessor :latch, :tc, :error_latch def self.controller_path 'test' @@ -204,6 +204,12 @@ module ActionController end def overfill_buffer_and_die + logger = ActionController::Base.logger || Logger.new($stdout) + response.stream.on_error do + logger.warn 'Error while streaming' + error_latch.count_down + end + # Write until the buffer is full. It doesn't expose that # information directly, so we must hard-code its size: 10.times do @@ -256,20 +262,12 @@ module ActionController end def test_set_cookie - @controller = TestController.new get :set_cookie assert_equal({'hello' => 'world'}, @response.cookies) assert_equal "hello world", @response.body end - def test_set_response! - @controller.set_response!(@request) - assert_kind_of(Live::Response, @controller.response) - assert_equal @request, @controller.response.request - end - def test_write_to_stream - @controller = TestController.new get :basic_stream assert_equal "helloworld", @response.body assert_equal 'text/event-stream', @response.headers['Content-Type'] @@ -281,10 +279,9 @@ module ActionController @controller.latch = Concurrent::CountDownLatch.new parts = ['hello', 'world'] - @controller.request = @request - @controller.response = @response + get :blocking_stream - t = Thread.new(@response) { |resp| + t = Thread.new(response) { |resp| resp.await_commit resp.stream.each do |part| assert_equal parts.shift, part @@ -294,38 +291,28 @@ module ActionController end } - @controller.process :blocking_stream - assert t.join(3), 'timeout expired before the thread terminated' end def test_abort_with_full_buffer @controller.latch = Concurrent::CountDownLatch.new - - @request.parameters[:format] = 'plain' - @controller.request = @request - @controller.response = @response - - got_error = Concurrent::CountDownLatch.new - @response.stream.on_error do - ActionController::Base.logger.warn 'Error while streaming' - got_error.count_down - end - - t = Thread.new(@response) { |resp| - resp.await_commit - _, _, body = resp.to_a - body.each do - @controller.latch.wait - body.close - break - end - } + @controller.error_latch = Concurrent::CountDownLatch.new capture_log_output do |output| - @controller.process :overfill_buffer_and_die + get :overfill_buffer_and_die, :format => 'plain' + + t = Thread.new(response) { |resp| + resp.await_commit + _, _, body = resp.to_a + body.each do + @controller.latch.wait + body.close + break + end + } + t.join - got_error.wait + @controller.error_latch.wait assert_match 'Error while streaming', output.rewind && output.read end end @@ -333,20 +320,18 @@ module ActionController def test_ignore_client_disconnect @controller.latch = Concurrent::CountDownLatch.new - @controller.request = @request - @controller.response = @response + capture_log_output do |output| + get :ignore_client_disconnect - t = Thread.new(@response) { |resp| - resp.await_commit - _, _, body = resp.to_a - body.each do - body.close - break - end - } + t = Thread.new(response) { |resp| + resp.await_commit + _, _, body = resp.to_a + body.each do + body.close + break + end + } - capture_log_output do |output| - @controller.process :ignore_client_disconnect t.join Timeout.timeout(3) do @controller.latch.wait @@ -364,11 +349,8 @@ module ActionController end def test_live_stream_default_header - @controller.request = @request - @controller.response = @response - @controller.process :default_header - _, headers, _ = @response.prepare! - assert headers['Content-Type'] + get :default_header + assert response.headers['Content-Type'] end def test_render_text @@ -437,13 +419,13 @@ module ActionController def test_stale_without_etag get :with_stale - assert_equal 200, @response.status.to_i + assert_equal 200, response.status.to_i end def test_stale_with_etag @request.if_none_match = Digest::MD5.hexdigest("123") get :with_stale - assert_equal 304, @response.status.to_i + assert_equal 304, response.status.to_i end end diff --git a/actionpack/test/controller/new_base/content_type_test.rb b/actionpack/test/controller/new_base/content_type_test.rb index 0445a837ca..d9899fe01f 100644 --- a/actionpack/test/controller/new_base/content_type_test.rb +++ b/actionpack/test/controller/new_base/content_type_test.rb @@ -7,12 +7,12 @@ module ContentType end def set_on_response_obj - response.content_type = Mime::RSS + response.content_type = Mime::Type[:RSS] render body: "Hello world!" end def set_on_render - render body: "Hello world!", content_type: Mime::RSS + render body: "Hello world!", content_type: Mime::Type[:RSS] end end diff --git a/actionpack/test/controller/params_wrapper_test.rb b/actionpack/test/controller/params_wrapper_test.rb index 8bf016d060..7226beed26 100644 --- a/actionpack/test/controller/params_wrapper_test.rb +++ b/actionpack/test/controller/params_wrapper_test.rb @@ -28,8 +28,17 @@ class ParamsWrapperTest < ActionController::TestCase end end - class User; end - class Person; end + class User + def self.attribute_names + [] + end + end + + class Person + def self.attribute_names + [] + end + end tests UsersController @@ -155,33 +164,28 @@ class ParamsWrapperTest < ActionController::TestCase end def test_derived_wrapped_keys_from_matching_model - User.expects(:respond_to?).with(:attribute_names).returns(true) - User.expects(:attribute_names).twice.returns(["username"]) - - with_default_wrapper_options do - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + assert_called(User, :attribute_names, times: 2, returns: ["username"]) do + with_default_wrapper_options do + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } + assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'user' => { 'username' => 'sikachu' }}) + end end end def test_derived_wrapped_keys_from_specified_model with_default_wrapper_options do - Person.expects(:respond_to?).with(:attribute_names).returns(true) - Person.expects(:attribute_names).twice.returns(["username"]) + assert_called(Person, :attribute_names, times: 2, returns: ["username"]) do + UsersController.wrap_parameters Person - UsersController.wrap_parameters Person - - @request.env['CONTENT_TYPE'] = 'application/json' - post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } - assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }}) + @request.env['CONTENT_TYPE'] = 'application/json' + post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } + assert_parameters({ 'username' => 'sikachu', 'title' => 'Developer', 'person' => { 'username' => 'sikachu' }}) + end end end def test_not_wrapping_abstract_model - User.expects(:respond_to?).with(:attribute_names).returns(true) - User.expects(:attribute_names).returns([]) - with_default_wrapper_options do @request.env['CONTENT_TYPE'] = 'application/json' post :parse, params: { 'username' => 'sikachu', 'title' => 'Developer' } diff --git a/actionpack/test/controller/redirect_test.rb b/actionpack/test/controller/redirect_test.rb index 91b30ede6a..631ff7d02a 100644 --- a/actionpack/test/controller/redirect_test.rb +++ b/actionpack/test/controller/redirect_test.rb @@ -266,15 +266,17 @@ class RedirectTest < ActionController::TestCase end def test_redirect_to_nil - assert_raise(ActionController::ActionControllerError) do + error = assert_raise(ActionController::ActionControllerError) do get :redirect_to_nil end + assert_equal "Cannot redirect to nil!", error.message end def test_redirect_to_params - assert_raise(ActionController::ActionControllerError) do + error = assert_raise(ActionController::ActionControllerError) do get :redirect_to_params end + assert_equal "Cannot redirect to a parameter hash!", error.message end def test_redirect_to_with_block diff --git a/actionpack/test/controller/render_other_test.rb b/actionpack/test/controller/render_other_test.rb index af50e11261..8891f6177f 100644 --- a/actionpack/test/controller/render_other_test.rb +++ b/actionpack/test/controller/render_other_test.rb @@ -12,7 +12,7 @@ class RenderOtherTest < ActionController::TestCase def test_using_custom_render_option ActionController.add_renderer :simon do |says, options| - self.content_type = Mime::TEXT + self.content_type = Mime::Type[:TEXT] self.response_body = "Simon says: #{says}" end diff --git a/actionpack/test/controller/render_xml_test.rb b/actionpack/test/controller/render_xml_test.rb index 7a91577b17..094d3ea1d2 100644 --- a/actionpack/test/controller/render_xml_test.rb +++ b/actionpack/test/controller/render_xml_test.rb @@ -92,6 +92,6 @@ class RenderXmlTest < ActionController::TestCase def test_should_use_implicit_content_type get :implicit_content_type, format: 'atom' - assert_equal Mime::ATOM, @response.content_type + assert_equal Mime::Type[:ATOM], @response.content_type end end diff --git a/actionpack/test/controller/renderer_test.rb b/actionpack/test/controller/renderer_test.rb index b55a25430b..16d24fa82a 100644 --- a/actionpack/test/controller/renderer_test.rb +++ b/actionpack/test/controller/renderer_test.rb @@ -1,6 +1,10 @@ require 'abstract_unit' class RendererTest < ActiveSupport::TestCase + test 'action controller base has a renderer' do + assert ActionController::Base.renderer + end + test 'creating with a controller' do controller = CommentsController renderer = ActionController::Renderer.for controller @@ -57,8 +61,7 @@ class RendererTest < ActiveSupport::TestCase end test 'rendering with defaults' do - renderer = ApplicationController.renderer - renderer.defaults[:https] = true + renderer = ApplicationController.renderer.new https: true content = renderer.render inline: '<%= request.ssl? %>' assert_equal 'true', content @@ -67,8 +70,8 @@ class RendererTest < ActiveSupport::TestCase test 'same defaults from the same controller' do renderer_defaults = ->(controller) { controller.renderer.defaults } - assert renderer_defaults[AccountsController].equal? renderer_defaults[AccountsController] - assert_not renderer_defaults[AccountsController].equal? renderer_defaults[CommentsController] + assert_equal renderer_defaults[AccountsController], renderer_defaults[AccountsController] + assert_equal renderer_defaults[AccountsController], renderer_defaults[CommentsController] end test 'rendering with different formats' do @@ -83,18 +86,6 @@ class RendererTest < ActiveSupport::TestCase test 'rendering with helpers' do assert_equal "<p>1\n<br />2</p>", render[inline: '<%= simple_format "1\n2" %>'] end - - test 'rendering from inherited renderer' do - inherited = Class.new ApplicationController.renderer do - defaults[:script_name] = 'script' - def render(options) - super options.merge(locals: { param: :value }) - end - end - - template = '<%= url_for controller: :foo, action: :bar, param: param %>' - assert_equal 'script/foo/bar?param=value', inherited.render(inline: template) - end private def render diff --git a/actionpack/test/controller/request_forgery_protection_test.rb b/actionpack/test/controller/request_forgery_protection_test.rb index 90fd8669c2..94ffbe3cd0 100644 --- a/actionpack/test/controller/request_forgery_protection_test.rb +++ b/actionpack/test/controller/request_forgery_protection_test.rb @@ -379,7 +379,6 @@ module RequestForgeryProtectionTests end def test_should_not_raise_error_if_token_is_not_a_string - @controller.unstub(:valid_authenticity_token?) assert_blocked do patch :index, params: { custom_authenticity_token: { foo: 'bar' } } end diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb index e767323773..f53f061e10 100644 --- a/actionpack/test/controller/rescue_test.rb +++ b/actionpack/test/controller/rescue_test.rb @@ -246,12 +246,15 @@ class RescueControllerTest < ActionController::TestCase end def test_rescue_handler_with_argument - @controller.expects(:show_errors).once.with { |e| e.is_a?(Exception) } - get :record_invalid + assert_called_with @controller, :show_errors, [Exception] do + get :record_invalid + end end + def test_rescue_handler_with_argument_as_string - @controller.expects(:show_errors).once.with { |e| e.is_a?(Exception) } - get :record_invalid_raise_as_string + assert_called_with @controller, :show_errors, [Exception] do + get :record_invalid_raise_as_string + end end def test_proc_rescue_handler diff --git a/actionpack/test/controller/send_file_test.rb b/actionpack/test/controller/send_file_test.rb index c0ddcf7f50..c712c75c88 100644 --- a/actionpack/test/controller/send_file_test.rb +++ b/actionpack/test/controller/send_file_test.rb @@ -20,6 +20,47 @@ class SendFileController < ActionController::Base send_file(file_path, options) end + def test_send_file_headers_bang + options = { + :type => Mime::Type[:PNG], + :disposition => 'disposition', + :filename => 'filename' + } + + send_data "foo", options + end + + def test_send_file_headers_with_disposition_as_a_symbol + options = { + :type => Mime::Type[:PNG], + :disposition => :disposition, + :filename => 'filename' + } + + send_data "foo", options + end + + def test_send_file_headers_with_mime_lookup_with_symbol + options = { :type => :png } + + send_data "foo", options + end + + def test_send_file_headers_with_bad_symbol + options = { :type => :this_type_is_not_registered } + send_data "foo", options + end + + def test_send_file_headers_with_nil_content_type + options = { :type => nil } + send_data "foo", options + end + + def test_send_file_headers_guess_type_from_extension + options = { :filename => params[:filename] } + send_data "foo", options + end + def data send_data(file_data, options) end @@ -88,62 +129,39 @@ class SendFileTest < ActionController::TestCase # Test that send_file_headers! is setting the correct HTTP headers. def test_send_file_headers_bang - options = { - :type => Mime::PNG, - :disposition => 'disposition', - :filename => 'filename' - } - # Do it a few times: the resulting headers should be identical # no matter how many times you send with the same options. # Test resolving Ticket #458. - @controller.headers = {} - @controller.send(:send_file_headers!, options) - @controller.send(:send_file_headers!, options) - @controller.send(:send_file_headers!, options) - - h = @controller.headers - assert_equal 'image/png', @controller.content_type - assert_equal 'disposition; filename="filename"', h['Content-Disposition'] - assert_equal 'binary', h['Content-Transfer-Encoding'] + 5.times do + get :test_send_file_headers_bang - # test overriding Cache-Control: no-cache header to fix IE open/save dialog - @controller.send(:send_file_headers!, options) - @controller.response.prepare! - assert_equal 'private', h['Cache-Control'] + assert_equal 'image/png', response.content_type + assert_equal 'disposition; filename="filename"', response.get_header('Content-Disposition') + assert_equal 'binary', response.get_header('Content-Transfer-Encoding') + assert_equal 'private', response.get_header('Cache-Control') + end end def test_send_file_headers_with_disposition_as_a_symbol - options = { - :type => Mime::PNG, - :disposition => :disposition, - :filename => 'filename' - } + get :test_send_file_headers_with_disposition_as_a_symbol - @controller.headers = {} - @controller.send(:send_file_headers!, options) - assert_equal 'disposition; filename="filename"', @controller.headers['Content-Disposition'] + assert_equal 'disposition; filename="filename"', response.get_header('Content-Disposition') end def test_send_file_headers_with_mime_lookup_with_symbol - options = { - :type => :png - } - - @controller.headers = {} - @controller.send(:send_file_headers!, options) - - assert_equal 'image/png', @controller.content_type + get __method__ + assert_equal 'image/png', response.content_type end def test_send_file_headers_with_bad_symbol - options = { - :type => :this_type_is_not_registered - } + error = assert_raise(ArgumentError) { get __method__ } + assert_equal "Unknown MIME type this_type_is_not_registered", error.message + end - @controller.headers = {} - assert_raise(ArgumentError) { @controller.send(:send_file_headers!, options) } + def test_send_file_headers_with_nil_content_type + error = assert_raise(ArgumentError) { get __method__ } + assert_equal ":type option required", error.message end def test_send_file_headers_guess_type_from_extension @@ -158,10 +176,8 @@ class SendFileTest < ActionController::TestCase 'file.unk' => 'application/octet-stream', 'zip' => 'application/octet-stream' }.each do |filename,expected_type| - options = { :filename => filename } - @controller.headers = {} - @controller.send(:send_file_headers!, options) - assert_equal expected_type, @controller.content_type + get __method__, params: { filename: filename } + assert_equal expected_type, response.content_type end end diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb index b3c3979c84..40c97abd35 100644 --- a/actionpack/test/controller/test_case_test.rb +++ b/actionpack/test/controller/test_case_test.rb @@ -627,6 +627,31 @@ XML assert_equal "application/json", parsed_env["CONTENT_TYPE"] end + def test_mutating_content_type_headers_for_plain_text_files_sets_the_header + @request.headers['Content-Type'] = 'text/plain' + post :render_body, params: { name: 'foo.txt' } + + assert_equal 'text/plain', @request.headers['Content-type'] + assert_equal 'foo.txt', @request.request_parameters[:name] + assert_equal 'render_body', @request.path_parameters[:action] + end + + def test_mutating_content_type_headers_for_html_files_sets_the_header + @request.headers['Content-Type'] = 'text/html' + post :render_body, params: { name: 'foo.html' } + + assert_equal 'text/html', @request.headers['Content-type'] + assert_equal 'foo.html', @request.request_parameters[:name] + assert_equal 'render_body', @request.path_parameters[:action] + end + + def test_mutating_content_type_headers_for_non_registered_mime_type_raises_an_error + assert_raises(RuntimeError) do + @request.headers['Content-Type'] = 'type/fake' + post :render_body, params: { name: 'foo.fake' } + end + end + def test_id_converted_to_string get :test_params, params: { id: 20, foo: Object.new @@ -949,6 +974,11 @@ class ResponseDefaultHeadersTest < ActionController::TestCase headers.delete params[:header] head :ok, 'C' => '3' end + + # Render a head response, but don't touch default headers + def leave_alone + head :ok + end end def before_setup @@ -974,9 +1004,13 @@ class ResponseDefaultHeadersTest < ActionController::TestCase end test "response contains default headers" do + get :leave_alone + # Response headers start out with the defaults - assert_equal @defaults, response.headers + assert_equal @defaults.merge('Content-Type' => 'text/html'), response.headers + end + test "response deletes a default header" do get :remove_header, params: { header: 'A' } assert_response :ok diff --git a/actionpack/test/controller/url_for_integration_test.rb b/actionpack/test/controller/url_for_integration_test.rb index 0e4c2b7c32..dfc2712e3e 100644 --- a/actionpack/test/controller/url_for_integration_test.rb +++ b/actionpack/test/controller/url_for_integration_test.rb @@ -158,6 +158,7 @@ module ActionPack ['/posts/ping',[ { :controller => 'posts', :action => 'ping' }]], ['/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1' }]], + ['/posts/show/1',[ { :controller => 'posts', :action => 'show', :id => '1', :format => '' }]], ['/posts',[ { :controller => 'posts' }]], ['/posts',[ { :controller => 'posts', :action => 'index' }]], ['/posts/create',[ { :action => 'create' }, {:day=>nil, :month=>nil, :controller=>"posts", :action=>"show_date"}, '/blog']], diff --git a/actionpack/test/controller/url_for_test.rb b/actionpack/test/controller/url_for_test.rb index 31677f202d..78e883f134 100644 --- a/actionpack/test/controller/url_for_test.rb +++ b/actionpack/test/controller/url_for_test.rb @@ -451,6 +451,26 @@ module AbstractController end end + def test_url_for_with_array_is_unmodified + with_routing do |set| + set.draw do + namespace :admin do + resources :posts + end + end + + kls = Class.new { include set.url_helpers } + kls.default_url_options[:host] = 'www.basecamphq.com' + + original_components = [:new, :admin, :post, { param: 'value' }] + components = original_components.dup + + kls.new.url_for(components) + + assert_equal(original_components, components) + end + end + private def extract_params(url) url.split('?', 2).last.split('&').sort diff --git a/actionpack/test/controller/webservice_test.rb b/actionpack/test/controller/webservice_test.rb index b26f037c36..2aee914a24 100644 --- a/actionpack/test/controller/webservice_test.rb +++ b/actionpack/test/controller/webservice_test.rb @@ -65,7 +65,7 @@ class WebServiceTest < ActionDispatch::IntegrationTest def test_register_and_use_json_simple with_test_route_set do - with_params_parsers Mime::JSON => Proc.new { |data| ActiveSupport::JSON.decode(data)['request'].with_indifferent_access } do + with_params_parsers Mime::Type[:JSON] => Proc.new { |data| ActiveSupport::JSON.decode(data)['request'].with_indifferent_access } do post "/", params: '{"request":{"summary":"content...","title":"JSON"}}', headers: { 'CONTENT_TYPE' => 'application/json' } @@ -97,24 +97,28 @@ class WebServiceTest < ActionDispatch::IntegrationTest end def test_parsing_json_doesnot_rescue_exception - with_test_route_set do - with_params_parsers Mime::JSON => Proc.new { |data| raise Interrupt } do - assert_raises(Interrupt) do - post "/", - params: '{"title":"JSON"}}', - headers: { 'CONTENT_TYPE' => 'application/json' } - end + req = Class.new(ActionDispatch::Request) do + def params_parsers + { Mime::Type[:JSON] => Proc.new { |data| raise Interrupt } } end + + def content_length; get_header('rack.input').length; end + end.new({ 'rack.input' => StringIO.new('{"title":"JSON"}}'), 'CONTENT_TYPE' => 'application/json' }) + + assert_raises(Interrupt) do + req.request_parameters end end private def with_params_parsers(parsers = {}) old_session = @integration_session - @app = ActionDispatch::ParamsParser.new(app.routes, parsers) + original_parsers = ActionDispatch::Request.parameter_parsers + ActionDispatch::Request.parameter_parsers = original_parsers.merge parsers reset! yield ensure + ActionDispatch::Request.parameter_parsers = original_parsers @integration_session = old_session end diff --git a/actionpack/test/dispatch/cookies_test.rb b/actionpack/test/dispatch/cookies_test.rb index 3454e60697..e9b2fe3214 100644 --- a/actionpack/test/dispatch/cookies_test.rb +++ b/actionpack/test/dispatch/cookies_test.rb @@ -653,6 +653,15 @@ class CookiesTest < ActionController::TestCase end end + def test_cookie_jar_mutated_by_request_persists_on_future_requests + get :authenticate + cookie_jar = @request.cookie_jar + cookie_jar.signed[:user_id] = 123 + assert_equal ["user_name", "user_id"], @request.cookie_jar.instance_variable_get(:@cookies).keys + get :get_signed_cookie + assert_equal ["user_name", "user_id"], @request.cookie_jar.instance_variable_get(:@cookies).keys + end + def test_raises_argument_error_if_missing_secret assert_raise(ArgumentError, nil.inspect) { @request.env["action_dispatch.key_generator"] = ActiveSupport::LegacyKeyGenerator.new(nil) diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index f9f379780c..93258fbceb 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -272,9 +272,12 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest test 'uses backtrace cleaner from env' do @app = DevelopmentApp - cleaner = stub(:clean => ['passed backtrace cleaner']) - get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => cleaner } - assert_match(/passed backtrace cleaner/, body) + backtrace_cleaner = ActiveSupport::BacktraceCleaner.new + + backtrace_cleaner.stub :clean, ['passed backtrace cleaner'] do + get "/", headers: { 'action_dispatch.show_exceptions' => true, 'action_dispatch.backtrace_cleaner' => backtrace_cleaner } + assert_match(/passed backtrace cleaner/, body) + end end test 'logs exception backtrace when all lines silenced' do diff --git a/actionpack/test/dispatch/exception_wrapper_test.rb b/actionpack/test/dispatch/exception_wrapper_test.rb index f37cce4d45..dfbb91c0ca 100644 --- a/actionpack/test/dispatch/exception_wrapper_test.rb +++ b/actionpack/test/dispatch/exception_wrapper_test.rb @@ -25,27 +25,29 @@ module ActionDispatch exception = TestError.new("lib/file.rb:42:in `index'") wrapper = ExceptionWrapper.new(nil, exception) - wrapper.expects(:source_fragment).with('lib/file.rb', 42).returns('foo') - - assert_equal [ code: 'foo', line_number: 42 ], wrapper.source_extracts + assert_called_with(wrapper, :source_fragment, ['lib/file.rb', 42], returns: 'foo') do + assert_equal [ code: 'foo', line_number: 42 ], wrapper.source_extracts + end end test '#source_extracts works with Windows paths' do exc = TestError.new("c:/path/to/rails/app/controller.rb:27:in 'index':") wrapper = ExceptionWrapper.new(nil, exc) - wrapper.expects(:source_fragment).with('c:/path/to/rails/app/controller.rb', 27).returns('nothing') - assert_equal [ code: 'nothing', line_number: 27 ], wrapper.source_extracts + assert_called_with(wrapper, :source_fragment, ['c:/path/to/rails/app/controller.rb', 27], returns: 'nothing') do + assert_equal [ code: 'nothing', line_number: 27 ], wrapper.source_extracts + end end test '#source_extracts works with non standard backtrace' do exc = TestError.new('invalid') wrapper = ExceptionWrapper.new(nil, exc) - wrapper.expects(:source_fragment).with('invalid', 0).returns('nothing') - assert_equal [ code: 'nothing', line_number: 0 ], wrapper.source_extracts + assert_called_with(wrapper, :source_fragment, ['invalid', 0], returns: 'nothing') do + assert_equal [ code: 'nothing', line_number: 0 ], wrapper.source_extracts + end end test '#application_trace returns traces only from the application' do diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb index 3017a9c2d6..91f6f66fe3 100644 --- a/actionpack/test/dispatch/mime_type_test.rb +++ b/actionpack/test/dispatch/mime_type_test.rb @@ -13,76 +13,75 @@ class MimeTypeTest < ActiveSupport::TestCase test "unregister" do begin Mime::Type.register("text/x-mobile", :mobile) - assert defined?(Mime::MOBILE) - assert_equal Mime::MOBILE, Mime::LOOKUP['text/x-mobile'] - assert_equal Mime::MOBILE, Mime::EXTENSION_LOOKUP['mobile'] + assert Mime::Type.registered?(:MOBILE) + assert_equal Mime::Type[:MOBILE], Mime::LOOKUP['text/x-mobile'] + assert_equal Mime::Type[:MOBILE], Mime::EXTENSION_LOOKUP['mobile'] Mime::Type.unregister(:mobile) - assert !defined?(Mime::MOBILE), "Mime::MOBILE should not be defined" + assert !Mime.const_defined?(:MOBILE), "Mime::MOBILE should not be defined" assert !Mime::LOOKUP.has_key?('text/x-mobile'), "Mime::LOOKUP should not have key ['text/x-mobile]" assert !Mime::EXTENSION_LOOKUP.has_key?('mobile'), "Mime::EXTENSION_LOOKUP should not have key ['mobile]" ensure - Mime.module_eval { remove_const :MOBILE if const_defined?(:MOBILE) } Mime::LOOKUP.reject!{|key,_| key == 'text/x-mobile'} end end test "parse text with trailing star at the beginning" do accept = "text/*, text/html, application/json, multipart/form-data" - expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::VCF, Mime::XML, Mime::YAML, Mime::JSON, Mime::MULTIPART_FORM] + expect = [Mime::Type[:HTML], Mime::Type[:TEXT], Mime::Type[:JS], Mime::Type[:CSS], Mime::Type[:ICS], Mime::Type[:CSV], Mime::Type[:VCF], Mime::Type[:XML], Mime::Type[:YAML], Mime::Type[:JSON], Mime::Type[:MULTIPART_FORM]] parsed = Mime::Type.parse(accept) assert_equal expect, parsed end test "parse text with trailing star in the end" do accept = "text/html, application/json, multipart/form-data, text/*" - expect = [Mime::HTML, Mime::JSON, Mime::MULTIPART_FORM, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::VCF, Mime::XML, Mime::YAML] + expect = [Mime::Type[:HTML], Mime::Type[:JSON], Mime::Type[:MULTIPART_FORM], Mime::Type[:TEXT], Mime::Type[:JS], Mime::Type[:CSS], Mime::Type[:ICS], Mime::Type[:CSV], Mime::Type[:VCF], Mime::Type[:XML], Mime::Type[:YAML]] parsed = Mime::Type.parse(accept) assert_equal expect, parsed end test "parse text with trailing star" do accept = "text/*" - expect = [Mime::HTML, Mime::TEXT, Mime::JS, Mime::CSS, Mime::ICS, Mime::CSV, Mime::VCF, Mime::XML, Mime::YAML, Mime::JSON] + expect = [Mime::Type[:HTML], Mime::Type[:TEXT], Mime::Type[:JS], Mime::Type[:CSS], Mime::Type[:ICS], Mime::Type[:CSV], Mime::Type[:VCF], Mime::Type[:XML], Mime::Type[:YAML], Mime::Type[:JSON]] parsed = Mime::Type.parse(accept) assert_equal expect, parsed end test "parse application with trailing star" do accept = "application/*" - expect = [Mime::HTML, Mime::JS, Mime::XML, Mime::RSS, Mime::ATOM, Mime::YAML, Mime::URL_ENCODED_FORM, Mime::JSON, Mime::PDF, Mime::ZIP] + expect = [Mime::Type[:HTML], Mime::Type[:JS], Mime::Type[:XML], Mime::Type[:RSS], Mime::Type[:ATOM], Mime::Type[:YAML], Mime::Type[:URL_ENCODED_FORM], Mime::Type[:JSON], Mime::Type[:PDF], Mime::Type[:ZIP]] parsed = Mime::Type.parse(accept) assert_equal expect, parsed end test "parse without q" do accept = "text/xml,application/xhtml+xml,text/yaml,application/xml,text/html,image/png,text/plain,application/pdf,*/*" - expect = [Mime::HTML, Mime::XML, Mime::YAML, Mime::PNG, Mime::TEXT, Mime::PDF, Mime::ALL] + expect = [Mime::Type[:HTML], Mime::Type[:XML], Mime::Type[:YAML], Mime::Type[:PNG], Mime::Type[:TEXT], Mime::Type[:PDF], Mime::Type[:ALL]] assert_equal expect, Mime::Type.parse(accept) end test "parse with q" do accept = "text/xml,application/xhtml+xml,text/yaml; q=0.3,application/xml,text/html; q=0.8,image/png,text/plain; q=0.5,application/pdf,*/*; q=0.2" - expect = [Mime::HTML, Mime::XML, Mime::PNG, Mime::PDF, Mime::TEXT, Mime::YAML, Mime::ALL] + expect = [Mime::Type[:HTML], Mime::Type[:XML], Mime::Type[:PNG], Mime::Type[:PDF], Mime::Type[:TEXT], Mime::Type[:YAML], Mime::Type[:ALL]] assert_equal expect, Mime::Type.parse(accept) end test "parse single media range with q" do accept = "text/html;q=0.9" - expect = [Mime::HTML] + expect = [Mime::Type[:HTML]] assert_equal expect, Mime::Type.parse(accept) end test "parse arbitrary media type parameters" do accept = 'multipart/form-data; boundary="simple boundary"' - expect = [Mime::MULTIPART_FORM] + expect = [Mime::Type[: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" - expect = [Mime::HTML, Mime::XML, "image/*", Mime::TEXT, Mime::ALL] + expect = [Mime::Type[:HTML], Mime::Type[:XML], "image/*", Mime::Type[:TEXT], Mime::Type[:ALL]] assert_equal expect, Mime::Type.parse(accept).collect(&:to_s) end @@ -90,16 +89,15 @@ 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::Type[:ALL]] assert_equal expect, Mime::Type.parse(accept).collect(&:to_s) end test "custom type" do begin - Mime::Type.register("image/foo", :foo) - assert_nothing_raised do - assert_equal Mime::FOO, Mime::SET.last - end + type = Mime::Type.register("image/foo", :foo) + assert_equal Mime::Type[:FOO], type + assert Mime::Type.registered?(:FOO) ensure Mime::Type.unregister(:FOO) end @@ -109,7 +107,7 @@ class MimeTypeTest < ActiveSupport::TestCase begin Mime::Type.register "text/foobar", :foobar, ["text/foo", "text/bar"] %w[text/foobar text/foo text/bar].each do |type| - assert_equal Mime::FOOBAR, type + assert_equal Mime::Type[:FOOBAR], type end ensure Mime::Type.unregister(:FOOBAR) @@ -124,7 +122,7 @@ class MimeTypeTest < ActiveSupport::TestCase end Mime::Type.register("text/foo", :foo) - assert_equal [Mime::FOO], registered_mimes + assert_equal [Mime::Type[:FOO]], registered_mimes ensure Mime::Type.unregister(:FOO) end @@ -134,7 +132,7 @@ class MimeTypeTest < ActiveSupport::TestCase begin Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"] %w[foobar foo bar].each do |extension| - assert_equal Mime::FOOBAR, Mime::EXTENSION_LOOKUP[extension] + assert_equal Mime::Type[:FOOBAR], Mime::EXTENSION_LOOKUP[extension] end ensure Mime::Type.unregister(:FOOBAR) @@ -144,60 +142,67 @@ class MimeTypeTest < ActiveSupport::TestCase test "register alias" do begin Mime::Type.register_alias "application/xhtml+xml", :foobar - assert_equal Mime::HTML, Mime::EXTENSION_LOOKUP['foobar'] + assert_equal Mime::Type[:HTML], Mime::EXTENSION_LOOKUP['foobar'] ensure Mime::Type.unregister(:FOOBAR) end end test "type should be equal to symbol" do - assert_equal Mime::HTML, 'application/xhtml+xml' - assert_equal Mime::HTML, :html + assert_equal Mime::Type[:HTML], 'application/xhtml+xml' + assert_equal Mime::Type[:HTML], :html end test "type convenience methods" do - # Don't test Mime::ALL, since it Mime::ALL#html? == true + # Don't test Mime::Type[:ALL], since it Mime::Type[:ALL].html? == true 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.upcase) } - + # Remove custom Mime::Type instances set in other tests, like Mime::Type[:GIF] and Mime::Type[:IPHONE] + types.delete_if { |type| !Mime::Type.registered?(type.upcase) } types.each do |type| - mime = Mime.const_get(type.upcase) + mime = Mime::Type[type.upcase] assert mime.respond_to?("#{type}?"), "#{mime.inspect} does not respond to #{type}?" - assert mime.send("#{type}?"), "#{mime.inspect} is not #{type}?" + assert_equal type, mime.symbol, "#{mime.inspect} is not #{type}?" invalid_types = types - [type] - invalid_types.delete(:html) if Mime::Type.html_types.include?(type) - invalid_types.each { |other_type| assert !mime.send("#{other_type}?"), "#{mime.inspect} is #{other_type}?" } + invalid_types.delete(:html) + invalid_types.each { |other_type| + assert_not_equal mime.symbol, other_type, "#{mime.inspect} is #{other_type}?" + } end end test "mime all is html" do - assert Mime::ALL.all?, "Mime::ALL is not all?" - assert Mime::ALL.html?, "Mime::ALL is not html?" + assert Mime::Type[:ALL].all?, "Mime::ALL is not all?" + assert Mime::Type[:ALL].html?, "Mime::ALL is not html?" + end + + test "deprecated lookup" do + assert_deprecated do + assert Mime::ALL.all?, "Mime::ALL is not all?" + end end test "verifiable mime types" do 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.upcase) } + # Remove custom Mime::Type instances set in other tests, like Mime::Type[:GIF] and Mime::Type[:IPHONE] + all_types.delete_if { |type| !Mime::Type.registered?(type.upcase) } end test "references gives preference to symbols before strings" do - assert_equal :html, Mime::HTML.ref + assert_equal :html, Mime::Type[:HTML].ref another = Mime::Type.lookup("foo/bar") assert_nil another.to_sym assert_equal "foo/bar", another.ref end test "regexp matcher" do - assert Mime::JS =~ "text/javascript" - assert Mime::JS =~ "application/javascript" - assert Mime::JS !~ "text/html" - assert !(Mime::JS !~ "text/javascript") - assert !(Mime::JS !~ "application/javascript") - assert Mime::HTML =~ 'application/xhtml+xml' + assert Mime::Type[:JS] =~ "text/javascript" + assert Mime::Type[:JS] =~ "application/javascript" + assert Mime::Type[:JS] !~ "text/html" + assert !(Mime::Type[:JS] !~ "text/javascript") + assert !(Mime::Type[:JS] !~ "application/javascript") + assert Mime::Type[:HTML] =~ 'application/xhtml+xml' end end diff --git a/actionpack/test/dispatch/request/session_test.rb b/actionpack/test/dispatch/request/session_test.rb index 410e3194e2..ae0e7e93ed 100644 --- a/actionpack/test/dispatch/request/session_test.rb +++ b/actionpack/test/dispatch/request/session_test.rb @@ -110,7 +110,7 @@ module ActionDispatch Class.new { def load_session(env); [1, {}]; end def session_exists?(env); true; end - def destroy_session(env, id, options); 123; end + def delete_session(env, id, options); 123; end }.new end end diff --git a/actionpack/test/dispatch/request_test.rb b/actionpack/test/dispatch/request_test.rb index ff63c10e8d..40866595ed 100644 --- a/actionpack/test/dispatch/request_test.rb +++ b/actionpack/test/dispatch/request_test.rb @@ -749,84 +749,94 @@ end class RequestFormat < BaseRequestTest test "xml format" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => 'xml' }) - assert_equal Mime::XML, request.format + assert_called(request, :parameters, times: 2, returns: {format: :xml}) do + assert_equal Mime::Type[:XML], request.format + end end test "xhtml format" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => 'xhtml' }) - assert_equal Mime::HTML, request.format + assert_called(request, :parameters, times: 2, returns: {format: :xhtml}) do + assert_equal Mime::Type[:HTML], request.format + end end test "txt format" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => 'txt' }) - assert_equal Mime::TEXT, request.format + assert_called(request, :parameters, times: 2, returns: {format: :txt}) do + assert_equal Mime::Type[:TEXT], request.format + end end test "XMLHttpRequest" do request = stub_request( 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest', - 'HTTP_ACCEPT' => [Mime::JS, Mime::HTML, Mime::XML, "text/xml", Mime::ALL].join(",") + 'HTTP_ACCEPT' => [Mime::Type[:JS], Mime::Type[:HTML], Mime::Type[:XML], "text/xml", Mime::Type[:ALL]].join(",") ) - request.expects(:parameters).at_least_once.returns({}) - assert request.xhr? - assert_equal Mime::JS, request.format + + assert_called(request, :parameters, times: 1, returns: {}) do + assert request.xhr? + assert_equal Mime::Type[:JS], request.format + end end test "can override format with parameter negative" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => :txt }) - assert !request.format.xml? + assert_called(request, :parameters, times: 2, returns: {format: :txt}) do + assert !request.format.xml? + end end test "can override format with parameter positive" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => :xml }) - assert request.format.xml? + assert_called(request, :parameters, times: 2, returns: {format: :xml}) do + assert request.format.xml? + end end test "formats text/html with accept header" do request = stub_request 'HTTP_ACCEPT' => 'text/html' - assert_equal [Mime::HTML], request.formats + assert_equal [Mime::Type[:HTML]], request.formats end test "formats blank with accept header" do request = stub_request 'HTTP_ACCEPT' => '' - assert_equal [Mime::HTML], request.formats + assert_equal [Mime::Type[:HTML]], request.formats end test "formats XMLHttpRequest with accept header" do request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" - assert_equal [Mime::JS], request.formats + assert_equal [Mime::Type[:JS]], request.formats end test "formats application/xml with accept header" do request = stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8', 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest") - assert_equal [Mime::XML], request.formats + assert_equal [Mime::Type[:XML]], request.formats end test "formats format:text with accept header" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => :txt }) - assert_equal [Mime::TEXT], request.formats + assert_called(request, :parameters, times: 2, returns: {format: :txt}) do + assert_equal [Mime::Type[:TEXT]], request.formats + end end test "formats format:unknown with accept header" do request = stub_request - request.expects(:parameters).at_least_once.returns({ :format => :unknown }) - assert_instance_of Mime::NullType, request.format + assert_called(request, :parameters, times: 2, returns: {format: :unknown}) do + assert_instance_of Mime::NullType, request.format + end end test "format is not nil with unknown format" do request = stub_request - request.expects(:parameters).at_least_once.returns({ format: :hello }) - assert request.format.nil? - assert_not request.format.html? - assert_not request.format.xml? - assert_not request.format.json? + assert_called(request, :parameters, times: 2, returns: {format: :hello}) do + assert request.format.nil? + assert_not request.format.html? + assert_not request.format.xml? + assert_not request.format.json? + end end test "format does not throw exceptions when malformed parameters" do @@ -837,8 +847,9 @@ class RequestFormat < BaseRequestTest test "formats with xhr request" do request = stub_request 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" - request.expects(:parameters).at_least_once.returns({}) - assert_equal [Mime::JS], request.formats + assert_called(request, :parameters, times: 1, returns: {}) do + assert_equal [Mime::Type[:JS]], request.formats + end end test "ignore_accept_header" do @@ -847,30 +858,37 @@ class RequestFormat < BaseRequestTest begin request = stub_request 'HTTP_ACCEPT' => 'application/xml' - request.expects(:parameters).at_least_once.returns({}) - assert_equal [ Mime::HTML ], request.formats + assert_called(request, :parameters, times: 1, returns: {}) do + assert_equal [ Mime::Type[:HTML] ], request.formats + end request = stub_request 'HTTP_ACCEPT' => 'koz-asked/something-crazy' - request.expects(:parameters).at_least_once.returns({}) - assert_equal [ Mime::HTML ], request.formats + assert_called(request, :parameters, times: 1, returns: {}) do + assert_equal [ Mime::Type[:HTML] ], request.formats + end request = stub_request 'HTTP_ACCEPT' => '*/*;q=0.1' - request.expects(:parameters).at_least_once.returns({}) - assert_equal [ Mime::HTML ], request.formats + assert_called(request, :parameters, times: 1, returns: {}) do + assert_equal [ Mime::Type[:HTML] ], request.formats + end request = stub_request 'HTTP_ACCEPT' => 'application/jxw' - request.expects(:parameters).at_least_once.returns({}) - assert_equal [ Mime::HTML ], request.formats + assert_called(request, :parameters, times: 1, returns: {}) do + assert_equal [ Mime::Type[:HTML] ], request.formats + end request = stub_request 'HTTP_ACCEPT' => 'application/xml', 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" - request.expects(:parameters).at_least_once.returns({}) - assert_equal [ Mime::JS ], request.formats + + assert_called(request, :parameters, times: 1, returns: {}) do + assert_equal [ Mime::Type[:JS] ], request.formats + end request = stub_request 'HTTP_ACCEPT' => 'application/xml', 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" - request.expects(:parameters).at_least_once.returns({:format => :json}) - assert_equal [ Mime::JSON ], request.formats + assert_called(request, :parameters, times: 2, returns: {format: :json}) do + assert_equal [ Mime::Type[:JSON] ], request.formats + end ensure ActionDispatch::Request.ignore_accept_header = old_ignore_accept_header end @@ -879,7 +897,7 @@ end class RequestMimeType < BaseRequestTest test "content type" do - assert_equal Mime::HTML, stub_request('CONTENT_TYPE' => 'text/html').content_mime_type + assert_equal Mime::Type[:HTML], stub_request('CONTENT_TYPE' => 'text/html').content_mime_type end test "no content type" do @@ -887,11 +905,11 @@ class RequestMimeType < BaseRequestTest end test "content type is XML" do - assert_equal Mime::XML, stub_request('CONTENT_TYPE' => 'application/xml').content_mime_type + assert_equal Mime::Type[:XML], stub_request('CONTENT_TYPE' => 'application/xml').content_mime_type end test "content type with charset" do - assert_equal Mime::XML, stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8').content_mime_type + assert_equal Mime::Type[:XML], stub_request('CONTENT_TYPE' => 'application/xml; charset=UTF-8').content_mime_type end test "user agent" do @@ -904,9 +922,9 @@ class RequestMimeType < BaseRequestTest 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" ) - assert_equal nil, request.negotiate_mime([Mime::XML, Mime::JSON]) - assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::HTML]) - assert_equal Mime::HTML, request.negotiate_mime([Mime::XML, Mime::ALL]) + assert_equal nil, request.negotiate_mime([Mime::Type[:XML], Mime::Type[:JSON]]) + assert_equal Mime::Type[:HTML], request.negotiate_mime([Mime::Type[:XML], Mime::Type[:HTML]]) + assert_equal Mime::Type[:HTML], request.negotiate_mime([Mime::Type[:XML], Mime::Type[:ALL]]) end test "negotiate_mime with content_type" do @@ -915,19 +933,21 @@ class RequestMimeType < BaseRequestTest 'HTTP_X_REQUESTED_WITH' => "XMLHttpRequest" ) - assert_equal Mime::XML, request.negotiate_mime([Mime::XML, Mime::CSV]) + assert_equal Mime::Type[:XML], request.negotiate_mime([Mime::Type[:XML], Mime::Type[:CSV]]) end end class RequestParameters < BaseRequestTest test "parameters" do request = stub_request - request.expects(:request_parameters).at_least_once.returns({ "foo" => 1 }) - request.expects(:query_parameters).at_least_once.returns({ "bar" => 2 }) - assert_equal({"foo" => 1, "bar" => 2}, request.parameters) - assert_equal({"foo" => 1}, request.request_parameters) - assert_equal({"bar" => 2}, request.query_parameters) + assert_called(request, :request_parameters, times: 2, returns: {"foo" => 1}) do + assert_called(request, :query_parameters, times: 2, returns: {"bar" => 2}) do + assert_equal({"foo" => 1, "bar" => 2}, request.parameters) + assert_equal({"foo" => 1}, request.request_parameters) + assert_equal({"bar" => 2}, request.query_parameters) + end + end end test "parameters not accessible after rack parse error" do diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb index 780e7dc3e2..85cdcda655 100644 --- a/actionpack/test/dispatch/response_test.rb +++ b/actionpack/test/dispatch/response_test.rb @@ -4,7 +4,7 @@ require 'rack/content_length' class ResponseTest < ActiveSupport::TestCase def setup - @response = ActionDispatch::Response.new + @response = ActionDispatch::Response.create end def test_can_wait_until_commit @@ -49,6 +49,11 @@ class ResponseTest < ActiveSupport::TestCase assert_equal 'utf-8', @response.charset end + def test_setting_content_type_header_impacts_content_type_method + @response.headers['Content-Type'] = "application/aaron" + assert_equal 'application/aaron', @response.content_type + end + test "simple output" do @response.body = "Hello, World!" @@ -67,6 +72,13 @@ class ResponseTest < ActiveSupport::TestCase assert_equal 200, ActionDispatch::Response.new('200 OK').status end + def test_only_set_charset_still_defaults_to_text_html + response = ActionDispatch::Response.new + response.charset = "utf-16" + _,headers,_ = response.to_a + assert_equal "text/html; charset=utf-16", headers['Content-Type'] + end + test "utf8 output" do @response.body = [1090, 1077, 1089, 1090].pack("U*") @@ -137,12 +149,19 @@ class ResponseTest < ActiveSupport::TestCase status, headers, body = @response.to_a assert_equal "user_name=david; path=/", headers["Set-Cookie"] assert_equal({"user_name" => "david"}, @response.cookies) + end + test "multiple cookies" do + @response.set_cookie("user_name", :value => "david", :path => "/") @response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5)) status, headers, body = @response.to_a assert_equal "user_name=david; path=/\nlogin=foo%26bar; path=/; expires=Mon, 10 Oct 2005 05:00:00 -0000", headers["Set-Cookie"] assert_equal({"login" => "foo&bar", "user_name" => "david"}, @response.cookies) + end + test "delete cookies" do + @response.set_cookie("user_name", :value => "david", :path => "/") + @response.set_cookie("login", :value => "foo&bar", :path => "/", :expires => Time.utc(2005, 10, 10,5)) @response.delete_cookie("login") status, headers, body = @response.to_a assert_equal({"user_name" => "david", "login" => nil}, @response.cookies) @@ -166,13 +185,13 @@ class ResponseTest < ActiveSupport::TestCase test "read charset and content type" do resp = ActionDispatch::Response.new.tap { |response| response.charset = 'utf-16' - response.content_type = Mime::XML + response.content_type = Mime::Type[:XML] response.body = 'Hello' } resp.to_a assert_equal('utf-16', resp.charset) - assert_equal(Mime::XML, resp.content_type) + assert_equal(Mime::Type[:XML], resp.content_type) assert_equal('application/xml; charset=utf-16', resp.headers['Content-Type']) end @@ -198,7 +217,7 @@ class ResponseTest < ActiveSupport::TestCase 'X-Content-Type-Options' => 'nosniff', 'X-XSS-Protection' => '1;' } - resp = ActionDispatch::Response.new.tap { |response| + resp = ActionDispatch::Response.create.tap { |response| response.body = 'Hello' } resp.to_a @@ -217,7 +236,7 @@ class ResponseTest < ActiveSupport::TestCase ActionDispatch::Response.default_headers = { 'X-XX-XXXX' => 'Here is my phone number' } - resp = ActionDispatch::Response.new.tap { |response| + resp = ActionDispatch::Response.create.tap { |response| response.body = 'Hello' } resp.to_a @@ -305,7 +324,7 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest @app = lambda { |env| ActionDispatch::Response.new.tap { |resp| resp.charset = 'utf-16' - resp.content_type = Mime::XML + resp.content_type = Mime::Type[:XML] resp.body = 'Hello' }.to_a } @@ -314,7 +333,7 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest assert_response :success assert_equal('utf-16', @response.charset) - assert_equal(Mime::XML, @response.content_type) + assert_equal(Mime::Type[:XML], @response.content_type) assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type']) end @@ -330,7 +349,7 @@ class ResponseIntegrationTest < ActionDispatch::IntegrationTest assert_response :success assert_equal('utf-16', @response.charset) - assert_equal(Mime::XML, @response.content_type) + assert_equal(Mime::Type[:XML], @response.content_type) assert_equal('application/xml; charset=utf-16', @response.headers['Content-Type']) end diff --git a/actionpack/test/dispatch/routing/ipv6_redirect_test.rb b/actionpack/test/dispatch/routing/ipv6_redirect_test.rb new file mode 100644 index 0000000000..f1b2e8cfc7 --- /dev/null +++ b/actionpack/test/dispatch/routing/ipv6_redirect_test.rb @@ -0,0 +1,45 @@ +require 'abstract_unit' + +class IPv6IntegrationTest < ActionDispatch::IntegrationTest + Routes = ActionDispatch::Routing::RouteSet.new + include Routes.url_helpers + + class ::BadRouteRequestController < ActionController::Base + include Routes.url_helpers + def index + render :text => foo_path + end + + def foo + redirect_to :action => :index + end + end + + Routes.draw do + get "/", :to => 'bad_route_request#index', :as => :index + get "/foo", :to => "bad_route_request#foo", :as => :foo + end + + def _routes + Routes + end + + APP = build_app Routes + def app + APP + end + + test "bad IPv6 redirection" do + # def test_simple_redirect + request_env = { + 'REMOTE_ADDR' => 'fd07:2fa:6cff:2112:225:90ff:fec7:22aa', + 'HTTP_HOST' => '[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]:3000', + 'SERVER_NAME' => '[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]', + 'SERVER_PORT' => 3000 } + + get '/foo', env: request_env + assert_response :redirect + assert_equal 'http://[fd07:2fa:6cff:2112:225:90ff:fec7:22aa]:3000/', redirect_to_url + end + +end diff --git a/actionpack/test/dispatch/session/abstract_store_test.rb b/actionpack/test/dispatch/session/abstract_store_test.rb index 1c35144e6f..d38d1bbce6 100644 --- a/actionpack/test/dispatch/session/abstract_store_test.rb +++ b/actionpack/test/dispatch/session/abstract_store_test.rb @@ -10,13 +10,13 @@ module ActionDispatch super end - def get_session(env, sid) + def find_session(env, sid) sid ||= 1 session = @sessions[sid] ||= {} [sid, session] end - def set_session(env, sid, session, options) + def write_session(env, sid, session, options) @sessions[sid] = session end end diff --git a/actionpack/test/dispatch/ssl_test.rb b/actionpack/test/dispatch/ssl_test.rb index 017e9ba2dd..7a5b8393dc 100644 --- a/actionpack/test/dispatch/ssl_test.rb +++ b/actionpack/test/dispatch/ssl_test.rb @@ -1,230 +1,199 @@ 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"]] + HEADERS = Rack::Utils::HeaderHash.new 'Content-Type' => 'text/html' + + attr_accessor :app + + def build_app(headers: {}, ssl_options: {}) + headers = HEADERS.merge(headers) + ActionDispatch::SSL.new lambda { |env| [200, headers, []] }, ssl_options + end +end + +class RedirectSSLTest < SSLTest + def assert_not_redirected(url, headers: {}) + self.app = build_app + get url, headers: headers + assert_response :ok + end + + def assert_redirected(host: nil, port: nil, status: 301, body: [], + deprecated_host: nil, deprecated_port: nil, + from: 'http://a/b?c=d', to: from.sub('http', 'https')) + + self.app = build_app ssl_options: { + redirect: { host: host, port: port, status: status, body: body }, + host: deprecated_host, port: deprecated_port } + + get from + assert_response status + assert_redirected_to to + assert_equal body.join, @response.body end - def app - @app ||= ActionDispatch::SSL.new(default_app) + test 'https is not redirected' do + assert_not_redirected 'https://example.org' end - attr_writer :app - def test_allows_https_url - get "https://example.org/path?key=value" - assert_response :success + test 'proxied https is not redirected' do + assert_not_redirected 'http://example.org', headers: { 'HTTP_X_FORWARDED_PROTO' => 'https' } end - def test_allows_https_proxy_header_url - get "http://example.org/", headers: { 'HTTP_X_FORWARDED_PROTO' => "https" } - assert_response :success + test 'http is redirected to https' do + assert_redirected 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'] + test 'redirect with non-301 status' do + assert_redirected status: 307 end - def test_hsts_header_by_default - get "https://example.org/" - assert_equal "max-age=31536000", - response.headers['Strict-Transport-Security'] + test 'redirect with custom body' do + assert_redirected body: ['foo'] end - def test_no_hsts_with_insecure_connection - get "http://example.org/" - assert_not response.headers['Strict-Transport-Security'] + test 'redirect to specific host' do + assert_redirected host: 'ssl', to: 'https://ssl/b?c=d' 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'] + test 'redirect to default port' do + assert_redirected port: 443 end - def test_disable_hsts_header - self.app = ActionDispatch::SSL.new(default_app, :hsts => false) - get "https://example.org/" - assert_not response.headers['Strict-Transport-Security'] + test 'redirect to non-default port' do + assert_redirected port: 8443, to: 'https://a:8443/b?c=d' 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'] + test 'redirect to different host and non-default port' do + assert_redirected host: 'ssl', port: 8443, to: 'https://ssl:8443/b?c=d' end - def test_hsts_expires_with_duration - self.app = ActionDispatch::SSL.new(default_app, :hsts => { :expires => 1.year }) - get "https://example.org/" - assert_equal "max-age=31557600", - response.headers['Strict-Transport-Security'] + test 'redirect to different host including port' do + assert_redirected host: 'ssl:443', to: 'https://ssl:443/b?c=d' 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'] + test ':host is deprecated, moved within redirect: { host: … }' do + assert_deprecated do + assert_redirected deprecated_host: 'foo', to: 'https://foo/b?c=d' + end 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") + test ':port is deprecated, moved within redirect: { port: … }' do + assert_deprecated do + assert_redirected deprecated_port: 1, to: 'https://a:1/b?c=d' + end end +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"]] - }) +class StrictTransportSecurityTest < SSLTest + EXPECTED = 'max-age=15552000' - get "https://example.org/" - assert_equal ["problem=def; path=/; HttpOnly; secure"], - response.headers['Set-Cookie'].split("\n") + def assert_hsts(expected, url: 'https://example.org', hsts: {}, headers: {}) + self.app = build_app ssl_options: { hsts: hsts }, headers: headers + get url + assert_equal expected, response.headers['Strict-Transport-Security'] 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"]] - }) + test 'enabled by default' do + assert_hsts EXPECTED + end - get "https://example.org/" - assert_equal ["problem=def; path=/; HttpOnly; secure"], - response.headers['Set-Cookie'].split("\n") + test 'not sent with http:// responses' do + assert_hsts nil, url: 'http://example.org' 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"]] - }) + test 'defers to app-provided header' do + assert_hsts 'app-provided', headers: { 'Strict-Transport-Security' => 'app-provided' } + end - get "https://example.org/" - assert_equal ["problem=def; path=/; secure; HttpOnly"], - response.headers['Set-Cookie'].split("\n") + test 'hsts: true enables default settings' do + assert_hsts EXPECTED, hsts: true end + test 'hsts: false sets max-age to zero, clearing browser HSTS settings' do + assert_hsts 'max-age=0', hsts: false + end - def test_flag_cookies_as_secure_with_has_not_spaces_before - self.app = ActionDispatch::SSL.new(lambda { |env| - headers = { - 'Content-Type' => "text/html", - 'Set-Cookie' => "problem=def; path=/;secure; HttpOnly" - } - [200, headers, ["OK"]] - }) + test ':expires sets max-age' do + assert_hsts 'max-age=500', hsts: { expires: 500 } + end - get "https://example.org/" - assert_equal ["problem=def; path=/;secure; HttpOnly"], - response.headers['Set-Cookie'].split("\n") + test ':expires supports AS::Duration arguments' do + assert_hsts 'max-age=31557600', hsts: { expires: 1.year } end - def test_flag_cookies_as_secure_with_has_not_spaces_after - self.app = ActionDispatch::SSL.new(lambda { |env| - headers = { - 'Content-Type' => "text/html", - 'Set-Cookie' => "problem=def; path=/; secure;HttpOnly" - } - [200, headers, ["OK"]] - }) + test 'include subdomains' do + assert_hsts "#{EXPECTED}; includeSubDomains", hsts: { subdomains: true } + end - get "https://example.org/" - assert_equal ["problem=def; path=/; secure;HttpOnly"], - response.headers['Set-Cookie'].split("\n") + test 'exclude subdomains' do + assert_hsts EXPECTED, hsts: { subdomains: false } end - def test_flag_cookies_as_secure_with_ignore_case - self.app = ActionDispatch::SSL.new(lambda { |env| - headers = { - 'Content-Type' => "text/html", - 'Set-Cookie' => "problem=def; path=/; Secure; HttpOnly" - } - [200, headers, ["OK"]] - }) + test 'opt in to browser preload lists' do + assert_hsts "#{EXPECTED}; preload", hsts: { preload: true } + end - get "https://example.org/" - assert_equal ["problem=def; path=/; Secure; HttpOnly"], - response.headers['Set-Cookie'].split("\n") + test 'opt out of browser preload lists' do + assert_hsts EXPECTED, hsts: { preload: false } end +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'] +class SecureCookiesTest < SSLTest + DEFAULT = %(id=1; path=/\ntoken=abc; path=/; secure; HttpOnly) + + def get(**options) + self.app = build_app(**options) + super 'https://example.org' + end + + def assert_cookies(*expected) + assert_equal expected, response.headers['Set-Cookie'].split("\n") + end + + def test_flag_cookies_as_secure + get headers: { 'Set-Cookie' => DEFAULT } + assert_cookies 'id=1; path=/; secure', 'token=abc; path=/; secure; HttpOnly' 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'] + def test_flag_cookies_as_secure_at_end_of_line + get headers: { 'Set-Cookie' => 'problem=def; path=/; HttpOnly; secure' } + assert_cookies 'problem=def; path=/; HttpOnly; secure' + end + + def test_flag_cookies_as_secure_with_more_spaces_before + get headers: { 'Set-Cookie' => 'problem=def; path=/; HttpOnly; secure' } + assert_cookies 'problem=def; path=/; HttpOnly; secure' 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'] + def test_flag_cookies_as_secure_with_more_spaces_after + get headers: { 'Set-Cookie' => 'problem=def; path=/; secure; HttpOnly' } + assert_cookies 'problem=def; path=/; secure; HttpOnly' 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'] + def test_flag_cookies_as_secure_with_has_not_spaces_before + get headers: { 'Set-Cookie' => 'problem=def; path=/;secure; HttpOnly' } + assert_cookies 'problem=def; path=/;secure; HttpOnly' end - def test_redirect_to_host_with_port - self.app = ActionDispatch::SSL.new(default_app, :host => "ssl.example.org:443") - get "http://example.org/path?key=value" - assert_equal "https://ssl.example.org:443/path?key=value", - response.headers['Location'] + def test_flag_cookies_as_secure_with_has_not_spaces_after + get headers: { 'Set-Cookie' => 'problem=def; path=/; secure;HttpOnly' } + assert_cookies 'problem=def; path=/; secure;HttpOnly' 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'] + def test_flag_cookies_as_secure_with_ignore_case + get headers: { 'Set-Cookie' => 'problem=def; path=/; Secure; HttpOnly' } + assert_cookies 'problem=def; path=/; Secure; HttpOnly' 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'] + def test_no_cookies + get + assert_nil response.headers['Set-Cookie'] end def test_keeps_original_headers_behavior - headers = Rack::Utils::HeaderHash.new( - "Content-Type" => "text/html", - "Connection" => ["close"] - ) - self.app = ActionDispatch::SSL.new(lambda { |env| [200, headers, ["OK"]] }) - - get "https://example.org/" - assert_equal "close", response.headers["Connection"] + get headers: { 'Connection' => %w[close] } + assert_equal 'close', response.headers['Connection'] end end diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb index d512dae4e7..6a3af32946 100644 --- a/actionpack/test/journey/router_test.rb +++ b/actionpack/test/journey/router_test.rb @@ -1,4 +1,3 @@ -# encoding: UTF-8 require 'abstract_unit' module ActionDispatch |