aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack')
-rw-r--r--actionpack/CHANGELOG.md32
-rw-r--r--actionpack/MIT-LICENSE2
-rw-r--r--actionpack/actionpack.gemspec2
-rw-r--r--actionpack/lib/action_controller/metal/conditional_get.rb2
-rw-r--r--actionpack/lib/action_controller/metal/http_authentication.rb23
-rw-r--r--actionpack/lib/action_controller/metal/instrumentation.rb8
-rw-r--r--actionpack/lib/action_controller/renderer.rb2
-rw-r--r--actionpack/lib/action_controller/test_case.rb4
-rw-r--r--actionpack/lib/action_dispatch.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/callbacks.rb6
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_exceptions.rb51
-rw-r--r--actionpack/lib/action_dispatch/middleware/debug_view.rb50
-rw-r--r--actionpack/lib/action_dispatch/middleware/host_authorization.rb103
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb14
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb7
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb5
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb8
-rw-r--r--actionpack/lib/action_dispatch/testing/test_response.rb11
-rw-r--r--actionpack/lib/action_pack.rb2
-rw-r--r--actionpack/test/abstract/collector_test.rb2
-rw-r--r--actionpack/test/controller/action_pack_assertions_test.rb18
-rw-r--r--actionpack/test/controller/filters_test.rb16
-rw-r--r--actionpack/test/controller/integration_test.rb2
-rw-r--r--actionpack/test/controller/parameters/parameters_permit_test.rb58
-rw-r--r--actionpack/test/controller/rescue_test.rb26
-rw-r--r--actionpack/test/controller/routing_test.rb4
-rw-r--r--actionpack/test/controller/test_case_test.rb26
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb32
-rw-r--r--actionpack/test/dispatch/host_authorization_test.rb161
-rw-r--r--actionpack/test/dispatch/mime_type_test.rb62
-rw-r--r--actionpack/test/dispatch/request/json_params_parsing_test.rb58
-rw-r--r--actionpack/test/dispatch/response_test.rb2
-rw-r--r--actionpack/test/dispatch/system_testing/screenshot_helper_test.rb20
33 files changed, 547 insertions, 276 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md
index 740c6db06f..95da4265a4 100644
--- a/actionpack/CHANGELOG.md
+++ b/actionpack/CHANGELOG.md
@@ -1,3 +1,31 @@
+* Introduce ActionDispatch::HostAuthorization
+
+ This is a new middleware that guards against DNS rebinding attacks by
+ white-listing the allowed hosts a request can be made to.
+
+ Each host is checked with the case operator (`#===`) to support `RegExp`,
+ `Proc`, `IPAddr` and custom objects as host allowances.
+
+ *Genadi Samokovarov*
+
+* Allow using `parsed_body` in `ActionController::TestCase`.
+
+ In addition to `ActionDispatch::IntegrationTest`, allow using
+ `parsed_body` in `ActionController::TestCase`:
+
+ ```
+ class SomeControllerTest < ActionController::TestCase
+ def test_some_action
+ post :action, body: { foo: 'bar' }
+ assert_equal({ "foo" => "bar" }, response.parsed_body)
+ end
+ end
+ ```
+
+ Fixes #34676.
+
+ *Tobias Bühlmann*
+
* Raise an error on root route naming conflicts.
Raises an ArgumentError when multiple root routes are defined in the
@@ -165,9 +193,9 @@
*Derek Prior*
-* Rails 6 requires Ruby 2.4.1 or newer.
+* Rails 6 requires Ruby 2.5.0 or newer.
- *Jeremy Daer*
+ *Jeremy Daer*, *Kasper Timm Hansen*
Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/actionpack/CHANGELOG.md) for previous changes.
diff --git a/actionpack/MIT-LICENSE b/actionpack/MIT-LICENSE
index 1cb3add0fc..ab7c27c209 100644
--- a/actionpack/MIT-LICENSE
+++ b/actionpack/MIT-LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2018 David Heinemeier Hansson
+Copyright (c) 2004-2019 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/actionpack/actionpack.gemspec b/actionpack/actionpack.gemspec
index ec56de18f1..c4c755b7ac 100644
--- a/actionpack/actionpack.gemspec
+++ b/actionpack/actionpack.gemspec
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.summary = "Web-flow and rendering framework putting the VC in MVC (part of Rails)."
s.description = "Web apps on Rails. Simple, battle-tested conventions for building and testing MVC web applications. Works with any Rack-compatible server."
- s.required_ruby_version = ">= 2.4.1"
+ s.required_ruby_version = ">= 2.5.0"
s.license = "MIT"
diff --git a/actionpack/lib/action_controller/metal/conditional_get.rb b/actionpack/lib/action_controller/metal/conditional_get.rb
index d6911ee2b5..29d1919ec5 100644
--- a/actionpack/lib/action_controller/metal/conditional_get.rb
+++ b/actionpack/lib/action_controller/metal/conditional_get.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/core_ext/hash/keys"
-
module ActionController
module ConditionalGet
extend ActiveSupport::Concern
diff --git a/actionpack/lib/action_controller/metal/http_authentication.rb b/actionpack/lib/action_controller/metal/http_authentication.rb
index 7036123d5d..6a274d35cb 100644
--- a/actionpack/lib/action_controller/metal/http_authentication.rb
+++ b/actionpack/lib/action_controller/metal/http_authentication.rb
@@ -69,21 +69,20 @@ module ActionController
extend ActiveSupport::Concern
module ClassMethods
- def http_basic_authenticate_with(options = {})
- before_action(options.except(:name, :password, :realm)) do
- authenticate_or_request_with_http_basic(options[:realm] || "Application") do |name, password|
- # This comparison uses & so that it doesn't short circuit and
- # uses `secure_compare` so that length information
- # isn't leaked.
- ActiveSupport::SecurityUtils.secure_compare(name, options[:name]) &
- ActiveSupport::SecurityUtils.secure_compare(password, options[:password])
- end
- end
+ def http_basic_authenticate_with(name:, password:, realm: nil, **options)
+ before_action(options) { http_basic_authenticate_or_request_with name: name, password: password, realm: realm }
+ end
+ end
+
+ def http_basic_authenticate_or_request_with(name:, password:, realm: nil, message: nil)
+ authenticate_or_request_with_http_basic(realm, message) do |given_name, given_password|
+ ActiveSupport::SecurityUtils.secure_compare(given_name, name) &
+ ActiveSupport::SecurityUtils.secure_compare(given_password, password)
end
end
- def authenticate_or_request_with_http_basic(realm = "Application", message = nil, &login_procedure)
- authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm, message)
+ def authenticate_or_request_with_http_basic(realm = nil, message = nil, &login_procedure)
+ authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm || "Application", message)
end
def authenticate_with_http_basic(&login_procedure)
diff --git a/actionpack/lib/action_controller/metal/instrumentation.rb b/actionpack/lib/action_controller/metal/instrumentation.rb
index be9449629f..51fac08749 100644
--- a/actionpack/lib/action_controller/metal/instrumentation.rb
+++ b/actionpack/lib/action_controller/metal/instrumentation.rb
@@ -30,13 +30,11 @@ module ActionController
ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
- begin
- result = super
+ super.tap do
payload[:status] = response.status
- result
- ensure
- append_info_to_payload(payload)
end
+ ensure
+ append_info_to_payload(payload)
end
end
diff --git a/actionpack/lib/action_controller/renderer.rb b/actionpack/lib/action_controller/renderer.rb
index 2b4559c760..cf8c0159e2 100644
--- a/actionpack/lib/action_controller/renderer.rb
+++ b/actionpack/lib/action_controller/renderer.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require "active_support/core_ext/hash/keys"
-
module ActionController
# ActionController::Renderer allows you to render arbitrary templates
# without requirement of being in controller actions.
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 5d784ceb31..a643484d96 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -457,7 +457,7 @@ module ActionController
# respectively which will make tests more expressive.
#
# Note that the request method is not verified.
- def process(action, method: "GET", params: {}, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
+ def process(action, method: "GET", params: nil, session: nil, body: nil, flash: {}, format: nil, xhr: false, as: nil)
check_required_ivars
http_method = method.to_s.upcase
@@ -485,7 +485,7 @@ module ActionController
format ||= as
end
- parameters = params.symbolize_keys
+ parameters = (params || {}).symbolize_keys
if format
parameters[:format] = format
diff --git a/actionpack/lib/action_dispatch.rb b/actionpack/lib/action_dispatch.rb
index 0822cdc0a6..8f39b88d56 100644
--- a/actionpack/lib/action_dispatch.rb
+++ b/actionpack/lib/action_dispatch.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
#--
-# Copyright (c) 2004-2018 David Heinemeier Hansson
+# Copyright (c) 2004-2019 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -49,11 +49,13 @@ module ActionDispatch
end
autoload_under "middleware" do
+ autoload :HostAuthorization
autoload :RequestId
autoload :Callbacks
autoload :Cookies
autoload :DebugExceptions
autoload :DebugLocks
+ autoload :DebugView
autoload :ExceptionWrapper
autoload :Executor
autoload :Flash
diff --git a/actionpack/lib/action_dispatch/middleware/callbacks.rb b/actionpack/lib/action_dispatch/middleware/callbacks.rb
index 5b2ad36dd5..87fe19225b 100644
--- a/actionpack/lib/action_dispatch/middleware/callbacks.rb
+++ b/actionpack/lib/action_dispatch/middleware/callbacks.rb
@@ -24,10 +24,8 @@ module ActionDispatch
def call(env)
error = nil
result = run_callbacks :call do
- begin
- @app.call(env)
- rescue => error
- end
+ @app.call(env)
+ rescue => error
end
raise error if error
result
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
index 7669767ae3..61773d97a2 100644
--- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
@@ -3,53 +3,14 @@
require "action_dispatch/http/request"
require "action_dispatch/middleware/exception_wrapper"
require "action_dispatch/routing/inspector"
+
require "action_view"
require "action_view/base"
-require "pp"
-
module ActionDispatch
# This middleware is responsible for logging exceptions and
# showing a debugging page in case the request is local.
class DebugExceptions
- RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
-
- class DebugView < ActionView::Base
- def debug_params(params)
- clean_params = params.clone
- clean_params.delete("action")
- clean_params.delete("controller")
-
- if clean_params.empty?
- "None"
- else
- PP.pp(clean_params, +"", 200)
- end
- end
-
- def debug_headers(headers)
- if headers.present?
- headers.inspect.gsub(",", ",\n")
- else
- "None"
- end
- end
-
- def debug_hash(object)
- object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
- end
-
- def render(*)
- logger = ActionView::Base.logger
-
- if logger && logger.respond_to?(:silence)
- logger.silence { super }
- else
- super
- end
- end
- end
-
cattr_reader :interceptors, instance_accessor: false, default: []
def self.register_interceptor(object = nil, &block)
@@ -87,11 +48,9 @@ module ActionDispatch
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
@interceptors.each do |interceptor|
- begin
- interceptor.call(request, exception)
- rescue Exception
- log_error(request, wrapper)
- end
+ interceptor.call(request, exception)
+ rescue Exception
+ log_error(request, wrapper)
end
end
@@ -152,7 +111,7 @@ module ActionDispatch
end
def create_template(request, wrapper)
- DebugView.new([RESCUES_TEMPLATE_PATH],
+ DebugView.new(
request: request,
exception_wrapper: wrapper,
exception: wrapper.exception,
diff --git a/actionpack/lib/action_dispatch/middleware/debug_view.rb b/actionpack/lib/action_dispatch/middleware/debug_view.rb
new file mode 100644
index 0000000000..ac12dc13a1
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/debug_view.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+require "pp"
+
+require "action_view"
+require "action_view/base"
+
+module ActionDispatch
+ class DebugView < ActionView::Base # :nodoc:
+ RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
+
+ def initialize(assigns)
+ super([RESCUES_TEMPLATE_PATH], assigns)
+ end
+
+ def debug_params(params)
+ clean_params = params.clone
+ clean_params.delete("action")
+ clean_params.delete("controller")
+
+ if clean_params.empty?
+ "None"
+ else
+ PP.pp(clean_params, +"", 200)
+ end
+ end
+
+ def debug_headers(headers)
+ if headers.present?
+ headers.inspect.gsub(",", ",\n")
+ else
+ "None"
+ end
+ end
+
+ def debug_hash(object)
+ object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
+ end
+
+ def render(*)
+ logger = ActionView::Base.logger
+
+ if logger && logger.respond_to?(:silence)
+ logger.silence { super }
+ else
+ super
+ end
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/host_authorization.rb b/actionpack/lib/action_dispatch/middleware/host_authorization.rb
new file mode 100644
index 0000000000..447b70112a
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/host_authorization.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+require "action_dispatch/http/request"
+
+module ActionDispatch
+ # This middleware guards from DNS rebinding attacks by white-listing the
+ # hosts a request can be sent to.
+ #
+ # When a request comes to an unauthorized host, the +response_app+
+ # application will be executed and rendered. If no +response_app+ is given, a
+ # default one will run, which responds with +403 Forbidden+.
+ class HostAuthorization
+ class Permissions # :nodoc:
+ def initialize(hosts)
+ @hosts = sanitize_hosts(hosts)
+ end
+
+ def empty?
+ @hosts.empty?
+ end
+
+ def allows?(host)
+ @hosts.any? do |allowed|
+ allowed === host
+ rescue
+ # IPAddr#=== raises an error if you give it a hostname instead of
+ # IP. Treat similar errors as blocked access.
+ false
+ end
+ end
+
+ private
+
+ def sanitize_hosts(hosts)
+ Array(hosts).map do |host|
+ case host
+ when Regexp then sanitize_regexp(host)
+ when String then sanitize_string(host)
+ else host
+ end
+ end
+ end
+
+ def sanitize_regexp(host)
+ /\A#{host}\z/
+ end
+
+ def sanitize_string(host)
+ if host.start_with?(".")
+ /\A(.+\.)?#{Regexp.escape(host[1..-1])}\z/
+ else
+ host
+ end
+ end
+ end
+
+ DEFAULT_RESPONSE_APP = -> env do
+ request = Request.new(env)
+
+ format = request.xhr? ? "text/plain" : "text/html"
+ template = DebugView.new(host: request.host)
+ body = template.render(template: "rescues/blocked_host", layout: "rescues/layout")
+
+ [403, {
+ "Content-Type" => "#{format}; charset=#{Response.default_charset}",
+ "Content-Length" => body.bytesize.to_s,
+ }, [body]]
+ end
+
+ def initialize(app, hosts, response_app = nil)
+ @app = app
+ @permissions = Permissions.new(hosts)
+ @response_app = response_app || DEFAULT_RESPONSE_APP
+ end
+
+ def call(env)
+ return @app.call(env) if @permissions.empty?
+
+ request = Request.new(env)
+
+ if authorized?(request)
+ mark_as_authorized(request)
+ @app.call(env)
+ else
+ @response_app.call(env)
+ end
+ end
+
+ private
+
+ def authorized?(request)
+ origin_host = request.get_header("HTTP_HOST").to_s.sub(/:\d+\z/, "")
+ forwarded_host = request.x_forwarded_host.to_s.split(/,\s?/).last.to_s.sub(/:\d+\z/, "")
+
+ @permissions.allows?(origin_host) &&
+ (forwarded_host.blank? || @permissions.allows?(forwarded_host))
+ end
+
+ def mark_as_authorized(request)
+ request.set_header("action_dispatch.authorized_host", request.host)
+ end
+ end
+end
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index 35158f9062..a5667573f4 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -162,14 +162,12 @@ module ActionDispatch
# Split the comma-separated list into an array of strings.
ips = header.strip.split(/[,\s]+/)
ips.select do |ip|
- begin
- # Only return IPs that are valid according to the IPAddr#new method.
- range = IPAddr.new(ip).to_range
- # We want to make sure nobody is sneaking a netmask in.
- range.begin == range.end
- rescue ArgumentError
- nil
- end
+ # Only return IPs that are valid according to the IPAddr#new method.
+ range = IPAddr.new(ip).to_range
+ # We want to make sure nobody is sneaking a netmask in.
+ range.begin == range.end
+ rescue ArgumentError
+ nil
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb
new file mode 100644
index 0000000000..2fa78dd385
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb
@@ -0,0 +1,7 @@
+<header>
+ <h1>Blocked host: <%= @host %></h1>
+</header>
+<div id="container">
+ <h2>To allow requests to <%= @host %>, add the following configuration:</h2>
+ <pre>Rails.application.config.hosts &lt;&lt; "<%= @host %>"</pre>
+</div>
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb
new file mode 100644
index 0000000000..4e2d1d0b08
--- /dev/null
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb
@@ -0,0 +1,5 @@
+Blocked host: <%= @host %>
+
+To allow requests to <%= @host %>, add the following configuration:
+
+ Rails.application.config.hosts << "<%= @host %>"
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 2ae75b0da8..2966c969f6 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -90,11 +90,11 @@ module ActionDispatch
def clear!
@path_helpers.each do |helper|
- @path_helpers_module.send :remove_method, helper
+ @path_helpers_module.remove_method helper
end
@url_helpers.each do |helper|
- @url_helpers_module.send :remove_method, helper
+ @url_helpers_module.remove_method helper
end
@routes.clear
@@ -108,8 +108,8 @@ module ActionDispatch
url_name = :"#{name}_url"
if routes.key? key
- @path_helpers_module.send :undef_method, path_name
- @url_helpers_module.send :undef_method, url_name
+ @path_helpers_module.undef_method path_name
+ @url_helpers_module.undef_method url_name
end
routes[key] = route
define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
diff --git a/actionpack/lib/action_dispatch/testing/test_response.rb b/actionpack/lib/action_dispatch/testing/test_response.rb
index 1e6b21f235..7c1202dc0e 100644
--- a/actionpack/lib/action_dispatch/testing/test_response.rb
+++ b/actionpack/lib/action_dispatch/testing/test_response.rb
@@ -14,11 +14,6 @@ module ActionDispatch
new response.status, response.headers, response.body
end
- def initialize(*) # :nodoc:
- super
- @response_parser = RequestEncoder.parser(content_type)
- end
-
# Was the response successful?
def success?
ActiveSupport::Deprecation.warn(<<-MSG.squish)
@@ -47,7 +42,11 @@ module ActionDispatch
end
def parsed_body
- @parsed_body ||= @response_parser.call(body)
+ @parsed_body ||= response_parser.call(body)
+ end
+
+ def response_parser
+ @response_parser ||= RequestEncoder.parser(content_type)
end
end
end
diff --git a/actionpack/lib/action_pack.rb b/actionpack/lib/action_pack.rb
index 3f69109633..36ee77c693 100644
--- a/actionpack/lib/action_pack.rb
+++ b/actionpack/lib/action_pack.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
#--
-# Copyright (c) 2004-2018 David Heinemeier Hansson
+# Copyright (c) 2004-2019 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
diff --git a/actionpack/test/abstract/collector_test.rb b/actionpack/test/abstract/collector_test.rb
index a4770b66e1..6db045fcd7 100644
--- a/actionpack/test/abstract/collector_test.rb
+++ b/actionpack/test/abstract/collector_test.rb
@@ -30,7 +30,7 @@ module AbstractController
end
test "register mime types on method missing" do
- AbstractController::Collector.send(:remove_method, :js)
+ AbstractController::Collector.remove_method :js
begin
collector = MyCollector.new
assert_not_respond_to collector, :js
diff --git a/actionpack/test/controller/action_pack_assertions_test.rb b/actionpack/test/controller/action_pack_assertions_test.rb
index 763df3a776..ecb8c37e6b 100644
--- a/actionpack/test/controller/action_pack_assertions_test.rb
+++ b/actionpack/test/controller/action_pack_assertions_test.rb
@@ -276,16 +276,14 @@ class ActionPackAssertionsControllerTest < ActionController::TestCase
end
def test_assert_redirect_failure_message_with_protocol_relative_url
- begin
- process :redirect_external_protocol_relative
- assert_redirected_to "/foo"
- rescue ActiveSupport::TestCase::Assertion => ex
- assert_no_match(
- /#{request.protocol}#{request.host}\/\/www.rubyonrails.org/,
- ex.message,
- "protocol relative url was incorrectly normalized"
- )
- end
+ process :redirect_external_protocol_relative
+ assert_redirected_to "/foo"
+ rescue ActiveSupport::TestCase::Assertion => ex
+ assert_no_match(
+ /#{request.protocol}#{request.host}\/\/www.rubyonrails.org/,
+ ex.message,
+ "protocol relative url was incorrectly normalized"
+ )
end
def test_template_objects_exist
diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb
index 425a6e25cc..104c9eeade 100644
--- a/actionpack/test/controller/filters_test.rb
+++ b/actionpack/test/controller/filters_test.rb
@@ -457,6 +457,7 @@ class FilterTest < ActionController::TestCase
prepend_before_action :before_all
prepend_after_action :after_all
before_action :between_before_all_and_after_all
+ after_action :between_before_all_and_after_all
def before_all
@ran_filter ||= []
@@ -472,6 +473,7 @@ class FilterTest < ActionController::TestCase
@ran_filter ||= []
@ran_filter << "between_before_all_and_after_all"
end
+
def show
render plain: "hello"
end
@@ -765,7 +767,7 @@ class FilterTest < ActionController::TestCase
def test_running_prepended_before_and_after_action
test_process(PrependingBeforeAndAfterController)
- assert_equal %w( before_all between_before_all_and_after_all after_all ), @controller.instance_variable_get(:@ran_filter)
+ assert_equal %w( before_all between_before_all_and_after_all between_before_all_and_after_all after_all ), @controller.instance_variable_get(:@ran_filter)
end
def test_skipping_and_limiting_controller
@@ -998,16 +1000,12 @@ class YieldingAroundFiltersTest < ActionController::TestCase
def test_nested_actions
controller = ControllerWithNestedFilters
assert_nothing_raised do
- begin
- test_process(controller, "raises_both")
- rescue Before, After
- end
+ test_process(controller, "raises_both")
+ rescue Before, After
end
assert_raise Before do
- begin
- test_process(controller, "raises_both")
- rescue After
- end
+ test_process(controller, "raises_both")
+ rescue After
end
end
diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb
index 39ede1442a..b5503a9c64 100644
--- a/actionpack/test/controller/integration_test.rb
+++ b/actionpack/test/controller/integration_test.rb
@@ -152,7 +152,7 @@ class IntegrationTestTest < ActiveSupport::TestCase
assert_equal "pass", @test.foo
ensure
# leave other tests as unaffected as possible
- mixin.__send__(:remove_method, :method_missing)
+ mixin.remove_method :method_missing
end
end
end
diff --git a/actionpack/test/controller/parameters/parameters_permit_test.rb b/actionpack/test/controller/parameters/parameters_permit_test.rb
index d2fa0aa16e..fbfe24059b 100644
--- a/actionpack/test/controller/parameters/parameters_permit_test.rb
+++ b/actionpack/test/controller/parameters/parameters_permit_test.rb
@@ -365,17 +365,15 @@ class ParametersPermitTest < ActiveSupport::TestCase
end
test "permitted takes a default value when Parameters.permit_all_parameters is set" do
- begin
- ActionController::Parameters.permit_all_parameters = true
- params = ActionController::Parameters.new(person: {
- age: "32", name: { first: "David", last: "Heinemeier Hansson" }
- })
-
- assert_predicate params.slice(:person), :permitted?
- assert_predicate params[:person][:name], :permitted?
- ensure
- ActionController::Parameters.permit_all_parameters = false
- end
+ ActionController::Parameters.permit_all_parameters = true
+ params = ActionController::Parameters.new(person: {
+ age: "32", name: { first: "David", last: "Heinemeier Hansson" }
+ })
+
+ assert_predicate params.slice(:person), :permitted?
+ assert_predicate params[:person][:name], :permitted?
+ ensure
+ ActionController::Parameters.permit_all_parameters = false
end
test "permitting parameters as an array" do
@@ -396,16 +394,14 @@ class ParametersPermitTest < ActiveSupport::TestCase
end
test "to_h returns converted hash when .permit_all_parameters is set" do
- begin
- ActionController::Parameters.permit_all_parameters = true
- params = ActionController::Parameters.new(crab: "Senjougahara Hitagi")
-
- assert_instance_of ActiveSupport::HashWithIndifferentAccess, params.to_h
- assert_not_kind_of ActionController::Parameters, params.to_h
- assert_equal({ "crab" => "Senjougahara Hitagi" }, params.to_h)
- ensure
- ActionController::Parameters.permit_all_parameters = false
- end
+ ActionController::Parameters.permit_all_parameters = true
+ params = ActionController::Parameters.new(crab: "Senjougahara Hitagi")
+
+ assert_instance_of ActiveSupport::HashWithIndifferentAccess, params.to_h
+ assert_not_kind_of ActionController::Parameters, params.to_h
+ assert_equal({ "crab" => "Senjougahara Hitagi" }, params.to_h)
+ ensure
+ ActionController::Parameters.permit_all_parameters = false
end
test "to_hash raises UnfilteredParameters on unfiltered params" do
@@ -429,17 +425,15 @@ class ParametersPermitTest < ActiveSupport::TestCase
end
test "to_hash returns converted hash when .permit_all_parameters is set" do
- begin
- ActionController::Parameters.permit_all_parameters = true
- params = ActionController::Parameters.new(crab: "Senjougahara Hitagi")
-
- assert_instance_of Hash, params.to_hash
- assert_not_kind_of ActionController::Parameters, params.to_hash
- assert_equal({ "crab" => "Senjougahara Hitagi" }, params.to_hash)
- assert_equal({ "crab" => "Senjougahara Hitagi" }, params)
- ensure
- ActionController::Parameters.permit_all_parameters = false
- end
+ ActionController::Parameters.permit_all_parameters = true
+ params = ActionController::Parameters.new(crab: "Senjougahara Hitagi")
+
+ assert_instance_of Hash, params.to_hash
+ assert_not_kind_of ActionController::Parameters, params.to_hash
+ assert_equal({ "crab" => "Senjougahara Hitagi" }, params.to_hash)
+ assert_equal({ "crab" => "Senjougahara Hitagi" }, params)
+ ensure
+ ActionController::Parameters.permit_all_parameters = false
end
test "to_unsafe_h returns unfiltered params" do
diff --git a/actionpack/test/controller/rescue_test.rb b/actionpack/test/controller/rescue_test.rb
index 3c39373e55..089b0b94d4 100644
--- a/actionpack/test/controller/rescue_test.rb
+++ b/actionpack/test/controller/rescue_test.rb
@@ -62,14 +62,6 @@ class RescueController < ActionController::Base
render plain: exception.message
end
- rescue_from ActionView::TemplateError do
- render plain: "action_view templater error"
- end
-
- rescue_from IOError do
- render plain: "io error"
- end
-
rescue_from ActionDispatch::Http::Parameters::ParseError do
render plain: "parse error", status: :bad_request
end
@@ -79,19 +71,6 @@ class RescueController < ActionController::Base
def before_action_raises
end
- def raises
- render plain: "already rendered"
- raise "don't panic!"
- end
-
- def method_not_allowed
- raise ActionController::MethodNotAllowed.new(:get, :head, :put)
- end
-
- def not_implemented
- raise ActionController::NotImplemented.new(:get, :put)
- end
-
def not_authorized
raise NotAuthorized
end
@@ -351,10 +330,6 @@ class RescueTest < ActionDispatch::IntegrationTest
raise RecordInvalid
end
- def b00m
- raise "b00m"
- end
-
private
def show_errors(exception)
render plain: exception.message
@@ -382,7 +357,6 @@ class RescueTest < ActionDispatch::IntegrationTest
set.draw do
get "foo", to: ::RescueTest::TestController.action(:foo)
get "invalid", to: ::RescueTest::TestController.action(:invalid)
- get "b00m", to: ::RescueTest::TestController.action(:b00m)
end
yield
end
diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb
index 30f2a23b33..b378bb80b8 100644
--- a/actionpack/test/controller/routing_test.rb
+++ b/actionpack/test/controller/routing_test.rb
@@ -355,10 +355,10 @@ class LegacyRouteSetTests < ActiveSupport::TestCase
rs.draw { ActiveSupport::Deprecation.silence { get "/:controller/:action", action: /auth[-|_].+/ } }
assert_equal({ action: "auth_google", controller: "content" }, rs.recognize_path("/content/auth_google"))
- assert_equal({ action: "auth-facebook", controller: "content" }, rs.recognize_path("/content/auth-facebook"))
+ assert_equal({ action: "auth-twitter", controller: "content" }, rs.recognize_path("/content/auth-twitter"))
assert_equal "/content/auth_google", url_for(rs, controller: "content", action: "auth_google")
- assert_equal "/content/auth-facebook", url_for(rs, controller: "content", action: "auth-facebook")
+ assert_equal "/content/auth-twitter", url_for(rs, controller: "content", action: "auth-twitter")
end
def test_route_with_regexp_for_controller
diff --git a/actionpack/test/controller/test_case_test.rb b/actionpack/test/controller/test_case_test.rb
index 6fc70d6248..d1cd190747 100644
--- a/actionpack/test/controller/test_case_test.rb
+++ b/actionpack/test/controller/test_case_test.rb
@@ -156,6 +156,10 @@ XML
render html: '<body class="foo"></body>'.html_safe
end
+ def render_json
+ render json: request.raw_post
+ end
+
def boom
raise "boom!"
end
@@ -474,6 +478,18 @@ XML
)
end
+ def test_nil_params
+ get :test_params, params: nil
+ parsed_params = JSON.parse(@response.body)
+ assert_equal(
+ {
+ "action" => "test_params",
+ "controller" => "test_case_test/test"
+ },
+ parsed_params
+ )
+ end
+
def test_query_param_named_action
get :test_query_parameters, params: { action: "foobar" }
parsed_params = JSON.parse(@response.body)
@@ -965,6 +981,16 @@ XML
assert_equal "q=test2", @response.body
end
+
+ def test_parsed_body_without_as_option
+ post :render_json, body: { foo: "heyo" }
+ assert_equal({ "foo" => "heyo" }, response.parsed_body)
+ end
+
+ def test_parsed_body_with_as_option
+ post :render_json, body: { foo: "heyo" }.to_json, as: :json
+ assert_equal({ "foo" => "heyo" }, response.parsed_body)
+ end
end
class ResponseDefaultHeadersTest < ActionController::TestCase
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index 37399cfd07..c326f276bf 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -27,14 +27,12 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
def raise_nested_exceptions
+ raise "First error"
+ rescue
begin
- raise "First error"
+ raise "Second error"
rescue
- begin
- raise "Second error"
- rescue
- raise "Third error"
- end
+ raise "Third error"
end
end
@@ -290,22 +288,20 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
end
test "rescue with JSON format as fallback if API request format is not supported" do
- begin
- Mime::Type.register "text/wibble", :wibble
+ Mime::Type.register "text/wibble", :wibble
- ActionDispatch::IntegrationTest.register_encoder(:wibble,
- param_encoder: -> params { params })
+ ActionDispatch::IntegrationTest.register_encoder(:wibble,
+ param_encoder: -> params { params })
- @app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, :api)
+ @app = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp, :api)
- get "/index", headers: { "action_dispatch.show_exceptions" => true }, as: :wibble
- assert_response 500
- assert_equal "application/json", response.content_type
- assert_match(/RuntimeError: puke/, body)
+ get "/index", headers: { "action_dispatch.show_exceptions" => true }, as: :wibble
+ assert_response 500
+ assert_equal "application/json", response.content_type
+ assert_match(/RuntimeError: puke/, body)
- ensure
- Mime::Type.unregister :wibble
- end
+ ensure
+ Mime::Type.unregister :wibble
end
test "does not show filtered parameters" do
diff --git a/actionpack/test/dispatch/host_authorization_test.rb b/actionpack/test/dispatch/host_authorization_test.rb
new file mode 100644
index 0000000000..dae7b08ec1
--- /dev/null
+++ b/actionpack/test/dispatch/host_authorization_test.rb
@@ -0,0 +1,161 @@
+# frozen_string_literal: true
+
+require "abstract_unit"
+require "ipaddr"
+
+class HostAuthorizationTest < ActionDispatch::IntegrationTest
+ App = -> env { [200, {}, %w(Success)] }
+
+ test "blocks requests to unallowed host" do
+ @app = ActionDispatch::HostAuthorization.new(App, %w(only.com))
+
+ get "/"
+
+ assert_response :forbidden
+ assert_match "Blocked host: www.example.com", response.body
+ end
+
+ test "passes all requests to if the whitelist is empty" do
+ @app = ActionDispatch::HostAuthorization.new(App, nil)
+
+ get "/"
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+
+ test "passes requests to allowed host" do
+ @app = ActionDispatch::HostAuthorization.new(App, %w(www.example.com))
+
+ get "/"
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+
+ test "the whitelist could be a single element" do
+ @app = ActionDispatch::HostAuthorization.new(App, "www.example.com")
+
+ get "/"
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+
+ test "passes requests to allowed hosts with domain name notation" do
+ @app = ActionDispatch::HostAuthorization.new(App, ".example.com")
+
+ get "/"
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+
+ test "does not allow domain name notation in the HOST header itself" do
+ @app = ActionDispatch::HostAuthorization.new(App, ".example.com")
+
+ get "/", env: {
+ "HOST" => ".example.com",
+ }
+
+ assert_response :forbidden
+ assert_match "Blocked host: .example.com", response.body
+ end
+
+ test "checks for requests with #=== to support wider range of host checks" do
+ @app = ActionDispatch::HostAuthorization.new(App, [-> input { input == "www.example.com" }])
+
+ get "/"
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+
+ test "mark the host when authorized" do
+ @app = ActionDispatch::HostAuthorization.new(App, ".example.com")
+
+ get "/"
+
+ assert_equal "www.example.com", request.get_header("action_dispatch.authorized_host")
+ end
+
+ test "sanitizes regular expressions to prevent accidental matches" do
+ @app = ActionDispatch::HostAuthorization.new(App, [/w.example.co/])
+
+ get "/"
+
+ assert_response :forbidden
+ assert_match "Blocked host: www.example.com", response.body
+ end
+
+ test "blocks requests to unallowed host supporting custom responses" do
+ @app = ActionDispatch::HostAuthorization.new(App, ["w.example.co"], -> env do
+ [401, {}, %w(Custom)]
+ end)
+
+ get "/"
+
+ assert_response :unauthorized
+ assert_equal "Custom", body
+ end
+
+ test "blocks requests with spoofed X-FORWARDED-HOST" do
+ @app = ActionDispatch::HostAuthorization.new(App, [IPAddr.new("127.0.0.1")])
+
+ get "/", env: {
+ "HTTP_X_FORWARDED_HOST" => "127.0.0.1",
+ "HOST" => "www.example.com",
+ }
+
+ assert_response :forbidden
+ assert_match "Blocked host: 127.0.0.1", response.body
+ end
+
+ test "does not consider IP addresses in X-FORWARDED-HOST spoofed when disabled" do
+ @app = ActionDispatch::HostAuthorization.new(App, nil)
+
+ get "/", env: {
+ "HTTP_X_FORWARDED_HOST" => "127.0.0.1",
+ "HOST" => "www.example.com",
+ }
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+
+ test "detects localhost domain spoofing" do
+ @app = ActionDispatch::HostAuthorization.new(App, "localhost")
+
+ get "/", env: {
+ "HTTP_X_FORWARDED_HOST" => "localhost",
+ "HOST" => "www.example.com",
+ }
+
+ assert_response :forbidden
+ assert_match "Blocked host: localhost", response.body
+ end
+
+ test "forwarded hosts should be permitted" do
+ @app = ActionDispatch::HostAuthorization.new(App, "domain.com")
+
+ get "/", env: {
+ "HTTP_X_FORWARDED_HOST" => "sub.domain.com",
+ "HOST" => "domain.com",
+ }
+
+ assert_response :forbidden
+ assert_match "Blocked host: sub.domain.com", response.body
+ end
+
+ test "forwarded hosts are allowed when permitted" do
+ @app = ActionDispatch::HostAuthorization.new(App, ".domain.com")
+
+ get "/", env: {
+ "HTTP_X_FORWARDED_HOST" => "sub.domain.com",
+ "HOST" => "domain.com",
+ }
+
+ assert_response :ok
+ assert_equal "Success", body
+ end
+end
diff --git a/actionpack/test/dispatch/mime_type_test.rb b/actionpack/test/dispatch/mime_type_test.rb
index fa264417e1..45d91883c0 100644
--- a/actionpack/test/dispatch/mime_type_test.rb
+++ b/actionpack/test/dispatch/mime_type_test.rb
@@ -96,57 +96,47 @@ class MimeTypeTest < ActiveSupport::TestCase
end
test "custom type" do
- begin
- type = Mime::Type.register("image/foo", :foo)
- assert_equal type, Mime[:foo]
- ensure
- Mime::Type.unregister(:foo)
- end
+ type = Mime::Type.register("image/foo", :foo)
+ assert_equal type, Mime[:foo]
+ ensure
+ Mime::Type.unregister(:foo)
end
test "custom type with type aliases" do
- 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
- end
- ensure
- Mime::Type.unregister(:foobar)
+ 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
end
+ ensure
+ Mime::Type.unregister(:foobar)
end
test "register callbacks" do
- begin
- registered_mimes = []
- Mime::Type.register_callback do |mime|
- registered_mimes << mime
- end
-
- mime = Mime::Type.register("text/foo", :foo)
- assert_equal [mime], registered_mimes
- ensure
- Mime::Type.unregister(:foo)
+ registered_mimes = []
+ Mime::Type.register_callback do |mime|
+ registered_mimes << mime
end
+
+ mime = Mime::Type.register("text/foo", :foo)
+ assert_equal [mime], registered_mimes
+ ensure
+ Mime::Type.unregister(:foo)
end
test "custom type with extension aliases" do
- begin
- Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"]
- %w[foobar foo bar].each do |extension|
- assert_equal Mime[:foobar], Mime::EXTENSION_LOOKUP[extension]
- end
- ensure
- Mime::Type.unregister(:foobar)
+ Mime::Type.register "text/foobar", :foobar, [], [:foo, "bar"]
+ %w[foobar foo bar].each do |extension|
+ assert_equal Mime[:foobar], Mime::EXTENSION_LOOKUP[extension]
end
+ ensure
+ Mime::Type.unregister(:foobar)
end
test "register alias" do
- begin
- Mime::Type.register_alias "application/xhtml+xml", :foobar
- assert_equal Mime[:html], Mime::EXTENSION_LOOKUP["foobar"]
- ensure
- Mime::Type.unregister(:foobar)
- end
+ Mime::Type.register_alias "application/xhtml+xml", :foobar
+ assert_equal Mime[:html], Mime::EXTENSION_LOOKUP["foobar"]
+ ensure
+ Mime::Type.unregister(:foobar)
end
test "type should be equal to symbol" do
diff --git a/actionpack/test/dispatch/request/json_params_parsing_test.rb b/actionpack/test/dispatch/request/json_params_parsing_test.rb
index beab8e78b5..2a48a12497 100644
--- a/actionpack/test/dispatch/request/json_params_parsing_test.rb
+++ b/actionpack/test/dispatch/request/json_params_parsing_test.rb
@@ -74,17 +74,15 @@ class JsonParamsParsingTest < ActionDispatch::IntegrationTest
test "occurring a parse error if parsing unsuccessful" do
with_test_routing do
- begin
- $stderr = StringIO.new # suppress the log
- json = "[\"person]\": {\"name\": \"David\"}}"
- exception = assert_raise(ActionDispatch::Http::Parameters::ParseError) do
- post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => false }
- end
- assert_equal JSON::ParserError, exception.cause.class
- assert_equal exception.cause.message, exception.message
- ensure
- $stderr = STDERR
+ $stderr = StringIO.new # suppress the log
+ json = "[\"person]\": {\"name\": \"David\"}}"
+ exception = assert_raise(ActionDispatch::Http::Parameters::ParseError) do
+ post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => false }
end
+ assert_equal JSON::ParserError, exception.cause.class
+ assert_equal exception.cause.message, exception.message
+ ensure
+ $stderr = STDERR
end
end
@@ -157,31 +155,27 @@ class RootLessJSONParamsParsingTest < ActionDispatch::IntegrationTest
end
test "parses json params after custom json mime type registered" do
- begin
- Mime::Type.unregister :json
- Mime::Type.register "application/json", :json, %w(application/vnd.rails+json)
- assert_parses(
- { "user" => { "username" => "meinac" }, "username" => "meinac" },
- "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/json"
- )
- ensure
- Mime::Type.unregister :json
- Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
- end
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w(application/vnd.rails+json)
+ assert_parses(
+ { "user" => { "username" => "meinac" }, "username" => "meinac" },
+ "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/json"
+ )
+ ensure
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
end
test "parses json params after custom json mime type registered with synonym" do
- begin
- Mime::Type.unregister :json
- Mime::Type.register "application/json", :json, %w(application/vnd.rails+json)
- assert_parses(
- { "user" => { "username" => "meinac" }, "username" => "meinac" },
- "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/vnd.rails+json"
- )
- ensure
- Mime::Type.unregister :json
- Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
- end
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w(application/vnd.rails+json)
+ assert_parses(
+ { "user" => { "username" => "meinac" }, "username" => "meinac" },
+ "{\"username\": \"meinac\"}", "CONTENT_TYPE" => "application/vnd.rails+json"
+ )
+ ensure
+ Mime::Type.unregister :json
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
end
private
diff --git a/actionpack/test/dispatch/response_test.rb b/actionpack/test/dispatch/response_test.rb
index 0f37d074af..60817c1c4d 100644
--- a/actionpack/test/dispatch/response_test.rb
+++ b/actionpack/test/dispatch/response_test.rb
@@ -42,7 +42,7 @@ class ResponseTest < ActiveSupport::TestCase
def test_each_isnt_called_if_str_body_is_written
# Controller writes and reads response body
each_counter = 0
- @response.body = Object.new.tap { |o| o.singleton_class.send(:define_method, :each) { |&block| each_counter += 1; block.call "foo" } }
+ @response.body = Object.new.tap { |o| o.singleton_class.define_method(:each) { |&block| each_counter += 1; block.call "foo" } }
@response["X-Foo"] = @response.body
assert_equal 1, each_counter, "#each was not called once"
diff --git a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
index de79c05657..097ef8af29 100644
--- a/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
+++ b/actionpack/test/dispatch/system_testing/screenshot_helper_test.rb
@@ -41,22 +41,20 @@ class ScreenshotHelperTest < ActiveSupport::TestCase
end
test "display_image return artifact format when specify RAILS_SYSTEM_TESTING_SCREENSHOT environment" do
- begin
- original_output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"]
- ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = "artifact"
+ original_output_type = ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"]
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = "artifact"
- new_test = DrivenBySeleniumWithChrome.new("x")
+ new_test = DrivenBySeleniumWithChrome.new("x")
- assert_equal "artifact", new_test.send(:output_type)
+ assert_equal "artifact", new_test.send(:output_type)
- Rails.stub :root, Pathname.getwd do
- new_test.stub :passed?, false do
- assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, new_test.send(:display_image)
- end
+ Rails.stub :root, Pathname.getwd do
+ new_test.stub :passed?, false do
+ assert_match %r|url=artifact://.+?tmp/screenshots/failures_x\.png|, new_test.send(:display_image)
end
- ensure
- ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = original_output_type
end
+ ensure
+ ENV["RAILS_SYSTEM_TESTING_SCREENSHOT"] = original_output_type
end
test "image path returns the absolute path from root" do