Merge pull request #45867 from jdufresne/show-rescuable-exceptions

Make the test environment show rescuable exceptions in responses
This commit is contained in:
Rafael Mendonça França 2023-05-24 13:45:45 -04:00 committed by GitHub
commit 61accb7dea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 245 additions and 121 deletions

@ -29,7 +29,7 @@
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false

@ -1,3 +1,11 @@
* Change `action_dispatch.show_exceptions` to one of `:all`, `:rescuable`, or
`:none`. `:all` and `:none` behave the same as the previous `true` and
`false` respectively. The new `:rescuable` option will only show exceptions
that can be rescued (e.g. `ActiveRecord::RecordNotFound`). `:rescuable` is
now the default for the test environment.
*Jon Dufresne*
* `config.action_dispatch.cookies_serializer` now accepts `:message_pack` and
`:message_pack_allow_marshal` as serializers. These serializers require the
[`msgpack` gem](https://rubygems.org/gems/msgpack) (>= 1.7.0).

@ -191,13 +191,6 @@ def http_auth_salt
get_header "action_dispatch.http_auth_salt"
end
def show_exceptions? # :nodoc:
# We're treating `nil` as "unset", and we want the default setting to be
# `true`. This logic should be extracted to `env_config` and calculated
# once.
!(get_header("action_dispatch.show_exceptions") == false)
end
# Returns a symbol form of the #request_method.
def request_method_symbol
HTTP_METHOD_LOOKUP[request_method]

@ -40,7 +40,7 @@ def call(env)
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
invoke_interceptors(request, exception, wrapper)
raise exception unless request.show_exceptions?
raise exception unless wrapper.show?(request)
render_exception(request, exception, wrapper)
end

@ -174,6 +174,29 @@ def self.status_code_for_exception(class_name)
Rack::Utils.status_code(@@rescue_responses[class_name])
end
def show?(request)
# We're treating `nil` as "unset", and we want the default setting to be
# `:all`. This logic should be extracted to `env_config` and calculated
# once.
config = request.get_header("action_dispatch.show_exceptions")
# Include true and false for backwards compatibility.
case config
when :none
false
when :rescuable
rescue_response?
when true
ActionDispatch.deprecator.warn("Setting action_dispatch.show_exceptions to true is deprecated. Set to :all instead.")
true
when false
ActionDispatch.deprecator.warn("Setting action_dispatch.show_exceptions to false is deprecated. Set to :none instead.")
false
else
true
end
end
def rescue_response?
@@rescue_responses.key?(exception.class.name)
end

@ -31,18 +31,18 @@ def call(env)
@app.call(env)
rescue Exception => exception
request = ActionDispatch::Request.new env
if request.show_exceptions?
render_exception(request, exception)
backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
if wrapper.show?(request)
render_exception(request, wrapper)
else
raise exception
end
end
private
def render_exception(request, exception)
backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner"
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
status = wrapper.status_code
def render_exception(request, wrapper)
status = wrapper.status_code
request.set_header "action_dispatch.exception", wrapper.unwrapped_exception
request.set_header "action_dispatch.original_path", request.path_info
request.set_header "action_dispatch.original_request_method", request.raw_request_method

@ -9,7 +9,7 @@ class Railtie < Rails::Railtie # :nodoc:
config.action_dispatch = ActiveSupport::OrderedOptions.new
config.action_dispatch.x_sendfile_header = nil
config.action_dispatch.ip_spoofing_check = true
config.action_dispatch.show_exceptions = true
config.action_dispatch.show_exceptions = :all
config.action_dispatch.tld_length = 1
config.action_dispatch.ignore_accept_header = false
config.action_dispatch.rescue_templates = {}

@ -89,7 +89,7 @@ def setup
test "rendering with layout => true" do
assert_raise(ArgumentError) do
get "/render_action/basic/hello_world_with_layout", headers: { "action_dispatch.show_exceptions" => false }
get "/render_action/basic/hello_world_with_layout", headers: { "action_dispatch.show_exceptions" => :none }
end
end
@ -109,7 +109,7 @@ def setup
test "rendering with layout => 'greetings'" do
assert_raise(ActionView::MissingTemplate) do
get "/render_action/basic/hello_world_with_custom_layout", headers: { "action_dispatch.show_exceptions" => false }
get "/render_action/basic/hello_world_with_custom_layout", headers: { "action_dispatch.show_exceptions" => :none }
end
end
end

@ -79,7 +79,7 @@ class RenderTest < Rack::TestCase
end
assert_raises(AbstractController::DoubleRenderError) do
get "/render/double_render", headers: { "action_dispatch.show_exceptions" => false }
get "/render/double_render", headers: { "action_dispatch.show_exceptions" => :none }
end
end
end
@ -89,13 +89,13 @@ class TestOnlyRenderPublicActions < Rack::TestCase
# Only public methods on actual controllers are callable actions
test "raises an exception when a method of Object is called" do
assert_raises(AbstractController::ActionNotFound) do
get "/render/blank_render/clone", headers: { "action_dispatch.show_exceptions" => false }
get "/render/blank_render/clone", headers: { "action_dispatch.show_exceptions" => :none }
end
end
test "raises an exception when a private method is called" do
assert_raises(AbstractController::ActionNotFound) do
get "/render/blank_render/secretz", headers: { "action_dispatch.show_exceptions" => false }
get "/render/blank_render/secretz", headers: { "action_dispatch.show_exceptions" => :none }
end
end
end

@ -331,7 +331,7 @@ def call(env)
env["action_dispatch.content_security_policy"] = POLICY
env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" }
env["action_dispatch.content_security_policy_report_only"] = false
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end
@ -481,7 +481,7 @@ def call(env)
env["action_dispatch.content_security_policy"] = POLICY
env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" }
env["action_dispatch.content_security_policy_report_only"] = false
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end
@ -597,7 +597,7 @@ def call(env)
env["action_dispatch.content_security_policy"] = nil
env["action_dispatch.content_security_policy_nonce_generator"] = nil
env["action_dispatch.content_security_policy_report_only"] = false
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end
@ -653,7 +653,7 @@ def call(env)
env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" }
env["action_dispatch.content_security_policy_report_only"] = false
env["action_dispatch.content_security_policy_nonce_directives"] = %w(script-src)
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end
@ -725,7 +725,7 @@ def call(env)
env["action_dispatch.content_security_policy"] = POLICY
env["action_dispatch.content_security_policy_nonce_generator"] = proc { "iyhD0Yc0W+c=" }
env["action_dispatch.content_security_policy_report_only"] = false
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end

@ -137,21 +137,21 @@ def call(env)
test "skip diagnosis if not showing detailed exceptions" do
@app = ProductionApp
assert_raise RuntimeError do
get "/", headers: { "action_dispatch.show_exceptions" => true }
get "/", headers: { "action_dispatch.show_exceptions" => :all }
end
end
test "skip diagnosis if not showing exceptions" do
@app = DevelopmentApp
assert_raise RuntimeError do
get "/", headers: { "action_dispatch.show_exceptions" => false }
get "/", headers: { "action_dispatch.show_exceptions" => :none }
end
end
test "raise an exception on cascade pass" do
@app = ProductionApp
assert_raise ActionController::RoutingError do
get "/pass", headers: { "action_dispatch.show_exceptions" => true }
get "/pass", headers: { "action_dispatch.show_exceptions" => :all }
end
end
@ -159,14 +159,14 @@ def call(env)
boomer = Boomer.new(false)
@app = ActionDispatch::DebugExceptions.new(boomer)
assert_raise ActionController::RoutingError do
get "/pass", headers: { "action_dispatch.show_exceptions" => true }
get "/pass", headers: { "action_dispatch.show_exceptions" => :all }
end
assert boomer.closed, "Expected to close the response body"
end
test "displays routes in a table when a RoutingError occurs" do
@app = DevelopmentApp
get "/pass", headers: { "action_dispatch.show_exceptions" => true }
get "/pass", headers: { "action_dispatch.show_exceptions" => :all }
routing_table = body[/route_table.*<.table>/m]
assert_match "/:controller(/:action)(.:format)", routing_table
assert_match ":controller#:action", routing_table
@ -176,7 +176,7 @@ def call(env)
test "displays request and response info when a RoutingError occurs" do
@app = DevelopmentApp
get "/pass", headers: { "action_dispatch.show_exceptions" => true }
get "/pass", headers: { "action_dispatch.show_exceptions" => :all }
assert_select "h2", /Request/
assert_select "h2", /Response/
@ -185,37 +185,37 @@ def call(env)
test "rescue with diagnostics message" do
@app = DevelopmentApp
get "/", headers: { "action_dispatch.show_exceptions" => true }
get "/", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_match(/<body>/, body)
assert_match(/puke/, body)
get "/not_found", headers: { "action_dispatch.show_exceptions" => true }
get "/not_found", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_match(/<body>/, body)
assert_match(/#{AbstractController::ActionNotFound.name}/, body)
get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true }
get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 405
assert_match(/<body>/, body)
assert_match(/ActionController::MethodNotAllowed/, body)
get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => true }
get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 405
assert_match(/<body>/, body)
assert_match(/ActionController::UnknownHttpMethod/, body)
get "/bad_request", headers: { "action_dispatch.show_exceptions" => true }
get "/bad_request", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 400
assert_match(/<body>/, body)
assert_match(/ActionController::BadRequest/, body)
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 400
assert_match(/<body>/, body)
assert_match(/ActionController::ParameterMissing/, body)
get "/invalid_mimetype", headers: { "Accept" => "text/html,*", "action_dispatch.show_exceptions" => true }
get "/invalid_mimetype", headers: { "Accept" => "text/html,*", "action_dispatch.show_exceptions" => :all }
assert_response 406
assert_match(/<body>/, body)
assert_match(/ActionDispatch::Http::MimeNegotiation::InvalidType/, body)
@ -223,7 +223,7 @@ def call(env)
test "rescue with text error for xhr request" do
@app = DevelopmentApp
xhr_request_env = { "action_dispatch.show_exceptions" => true, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" }
xhr_request_env = { "action_dispatch.show_exceptions" => :all, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" }
get "/", headers: xhr_request_env
assert_response 500
@ -274,44 +274,44 @@ def call(env)
test "rescue with JSON error for JSON API request" do
@app = ApiApp
get "/", headers: { "action_dispatch.show_exceptions" => true }, as: :json
get "/", headers: { "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 500
assert_no_match(/<header>/, body)
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
assert_match(/RuntimeError: puke/, body)
get "/not_found", headers: { "action_dispatch.show_exceptions" => true }, as: :json
get "/not_found", headers: { "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 404
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
assert_match(/#{AbstractController::ActionNotFound.name}/, body)
get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => true }, as: :json
get "/method_not_allowed", headers: { "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 405
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
assert_match(/ActionController::MethodNotAllowed/, body)
get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => true }, as: :json
get "/unknown_http_method", headers: { "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 405
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
assert_match(/ActionController::UnknownHttpMethod/, body)
get "/bad_request", headers: { "action_dispatch.show_exceptions" => true }, as: :json
get "/bad_request", headers: { "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 400
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
assert_match(/ActionController::BadRequest/, body)
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }, as: :json
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 400
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
assert_match(/ActionController::ParameterMissing/, body)
get "/invalid_mimetype", headers: { "Accept" => "text/html,*", "action_dispatch.show_exceptions" => true }, as: :json
get "/invalid_mimetype", headers: { "Accept" => "text/html,*", "action_dispatch.show_exceptions" => :all }, as: :json
assert_response 406
assert_no_match(/<body>/, body)
assert_equal "application/json", response.media_type
@ -321,12 +321,12 @@ def call(env)
test "rescue with suggestions" do
@app = DevelopmentApp
get "/not_found", headers: { "action_dispatch.show_exceptions" => true }
get "/not_found", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_select("b", /Did you mean\?/)
assert_select("li", "hello")
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => true }
get "/parameter_missing", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 400
assert_select("b", /Did you mean\?/)
assert_select("li", "valid_param_key")
@ -335,7 +335,7 @@ def call(env)
test "rescue with HTML format for HTML API request" do
@app = ApiApp
get "/index.html", headers: { "action_dispatch.show_exceptions" => true }
get "/index.html", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_match(/<header>/, body)
assert_match(/<body>/, body)
@ -346,7 +346,7 @@ def call(env)
test "rescue with XML format for XML API requests" do
@app = ApiApp
get "/index.xml", headers: { "action_dispatch.show_exceptions" => true }
get "/index.xml", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_equal "application/xml", response.media_type
assert_match(/RuntimeError: puke/, body)
@ -360,7 +360,7 @@ def call(env)
@app = ApiApp
get "/index", headers: { "action_dispatch.show_exceptions" => true }, as: :wibble
get "/index", headers: { "action_dispatch.show_exceptions" => :all }, as: :wibble
assert_response 500
assert_equal "application/json", response.media_type
assert_match(/RuntimeError: puke/, body)
@ -372,7 +372,7 @@ def call(env)
test "does not show filtered parameters" do
@app = DevelopmentApp
get "/", params: { "foo" => "bar" }, headers: { "action_dispatch.show_exceptions" => true,
get "/", params: { "foo" => "bar" }, headers: { "action_dispatch.show_exceptions" => :all,
"action_dispatch.parameter_filter" => [:foo] }
assert_response 500
assert_match("&quot;foo&quot;=&gt;&quot;[FILTERED]&quot;", body)
@ -381,7 +381,7 @@ def call(env)
test "show registered original exception if the last exception is TemplateError" do
@app = DevelopmentApp
get "/not_found_original_exception", headers: { "action_dispatch.show_exceptions" => true }
get "/not_found_original_exception", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_match %r{AbstractController::ActionNotFound}, body
assert_match %r{Showing <i>.*test/dispatch/debug_exceptions_test.rb</i>}, body
@ -390,7 +390,7 @@ def call(env)
test "show the last exception and cause even when the cause is mapped to resque_responses" do
@app = DevelopmentApp
get "/cause_mapped_to_rescue_responses", headers: { "action_dispatch.show_exceptions" => true }
get "/cause_mapped_to_rescue_responses", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_match %r{ActionController::ParameterMissing}, body
assert_match %r{NameError}, body
@ -399,7 +399,7 @@ def call(env)
test "named URLs missing keys raise 500 level error" do
@app = DevelopmentApp
get "/missing_keys", headers: { "action_dispatch.show_exceptions" => true }
get "/missing_keys", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_match(/ActionController::UrlGenerationError/, body)
@ -408,7 +408,7 @@ def call(env)
test "show the controller name in the diagnostics template when controller name is present" do
@app = DevelopmentApp
get("/runtime_error", headers: {
"action_dispatch.show_exceptions" => true,
"action_dispatch.show_exceptions" => :all,
"action_dispatch.request.parameters" => {
"action" => "show",
"id" => "unknown",
@ -431,7 +431,7 @@ def call(env)
}
get("/runtime_error", headers: {
"action_dispatch.show_exceptions" => true,
"action_dispatch.show_exceptions" => :all,
"action_dispatch.request.parameters" => {
"action" => "show",
"controller" => "featured_tile"
@ -445,14 +445,14 @@ def call(env)
test "sets the HTTP charset parameter" do
@app = DevelopmentApp
get "/", headers: { "action_dispatch.show_exceptions" => true }
get "/", headers: { "action_dispatch.show_exceptions" => :all }
assert_equal "text/html; charset=utf-8", response.headers["Content-Type"]
end
test "uses logger from env" do
@app = DevelopmentApp
output = StringIO.new
get "/", headers: { "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => Logger.new(output) }
get "/", headers: { "action_dispatch.show_exceptions" => :all, "action_dispatch.logger" => Logger.new(output) }
assert_match(/puke/, output.rewind && output.read)
end
@ -463,7 +463,7 @@ def call(env)
_old, ActionView::Base.logger = ActionView::Base.logger, logger
begin
get "/", headers: { "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => logger }
get "/", headers: { "action_dispatch.show_exceptions" => :all, "action_dispatch.logger" => logger }
ensure
ActionView::Base.logger = _old
end
@ -487,7 +487,7 @@ def call(env)
_old, ActionView::Base.logger = ActionView::Base.logger, logger
begin
assert_nothing_raised do
get "/", headers: { "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => logger }
get "/", headers: { "action_dispatch.show_exceptions" => :all, "action_dispatch.logger" => logger }
end
ensure
ActionView::Base.logger = _old
@ -501,7 +501,7 @@ def call(env)
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 }
get "/", headers: { "action_dispatch.show_exceptions" => :all, "action_dispatch.backtrace_cleaner" => backtrace_cleaner }
assert_match(/passed backtrace cleaner/, body)
end
end
@ -513,7 +513,7 @@ def call(env)
backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
backtrace_cleaner.add_silencer { true }
env = { "action_dispatch.show_exceptions" => true,
env = { "action_dispatch.show_exceptions" => :all,
"action_dispatch.logger" => Logger.new(output),
"action_dispatch.backtrace_cleaner" => backtrace_cleaner }
@ -528,7 +528,7 @@ def call(env)
backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
backtrace_cleaner.add_silencer { true }
env = { "action_dispatch.show_exceptions" => true,
env = { "action_dispatch.show_exceptions" => :all,
"action_dispatch.logger" => Logger.new(output),
"action_dispatch.log_rescued_responses" => true,
"action_dispatch.backtrace_cleaner" => backtrace_cleaner }
@ -551,7 +551,7 @@ def call(env)
backtrace_cleaner.add_silencer { true }
env = { "Accept" => "text/html,*",
"action_dispatch.show_exceptions" => true,
"action_dispatch.show_exceptions" => :all,
"action_dispatch.logger" => Logger.new(output),
"action_dispatch.log_rescued_responses" => true,
"action_dispatch.backtrace_cleaner" => backtrace_cleaner }
@ -571,7 +571,7 @@ def call(env)
output = StringIO.new
env = { "action_dispatch.show_exceptions" => true,
env = { "action_dispatch.show_exceptions" => :all,
"action_dispatch.logger" => Logger.new(output),
"action_dispatch.log_rescued_responses" => false }
@ -585,7 +585,7 @@ def call(env)
output = StringIO.new
env = { "action_dispatch.show_exceptions" => true,
env = { "action_dispatch.show_exceptions" => :all,
"action_dispatch.logger" => Logger.new(output),
"action_dispatch.log_rescued_responses" => true }
@ -673,7 +673,7 @@ def call(env)
test "invoke interceptors before rendering" do
@app = InterceptedApp
get "/intercepted_error", headers: { "action_dispatch.show_exceptions" => true }
get "/intercepted_error", headers: { "action_dispatch.show_exceptions" => :all }
assert_equal InterceptedErrorInstance, request.get_header("int")
end
@ -681,7 +681,7 @@ def call(env)
test "bad interceptors doesn't debug exceptions" do
@app = BadInterceptedApp
get "/puke", headers: { "action_dispatch.show_exceptions" => true }
get "/puke", headers: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_match(/puke/, body)
@ -752,7 +752,7 @@ def call(env)
test "debug exceptions app shows diagnostics when malformed query parameters are provided by XHR" do
@app = DevelopmentApp
xhr_request_env = { "action_dispatch.show_exceptions" => true, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" }
xhr_request_env = { "action_dispatch.show_exceptions" => :all, "HTTP_X_REQUESTED_WITH" => "XMLHttpRequest" }
get "/bad_request?x[y]=1&x[y][][w]=2", headers: xhr_request_env

@ -185,5 +185,75 @@ def backtrace
]
}.inspect, wrapper.traces.inspect)
end
test "#show? returns false when using :rescuable and the exceptions is not rescuable" do
exception = RuntimeError.new("")
wrapper = ExceptionWrapper.new(nil, exception)
env = { "action_dispatch.show_exceptions" => :rescuable }
request = ActionDispatch::Request.new(env)
assert_equal false, wrapper.show?(request)
end
test "#show? returns true when using :rescuable and the exceptions is rescuable" do
exception = AbstractController::ActionNotFound.new("")
wrapper = ExceptionWrapper.new(nil, exception)
env = { "action_dispatch.show_exceptions" => :rescuable }
request = ActionDispatch::Request.new(env)
assert_equal true, wrapper.show?(request)
end
test "#show? returns false when using :none and the exceptions is rescuable" do
exception = AbstractController::ActionNotFound.new("")
wrapper = ExceptionWrapper.new(nil, exception)
env = { "action_dispatch.show_exceptions" => :none }
request = ActionDispatch::Request.new(env)
assert_equal false, wrapper.show?(request)
end
test "#show? returns true when using :all and the exceptions is not rescuable" do
exception = RuntimeError.new("")
wrapper = ExceptionWrapper.new(nil, exception)
env = { "action_dispatch.show_exceptions" => :all }
request = ActionDispatch::Request.new(env)
assert_equal true, wrapper.show?(request)
end
test "#show? emits a deprecation when show_exceptions is true" do
exception = RuntimeError.new("")
wrapper = ExceptionWrapper.new(nil, exception)
env = { "action_dispatch.show_exceptions" => true }
request = ActionDispatch::Request.new(env)
msg = "Setting action_dispatch.show_exceptions to true is deprecated. Set to :all instead."
result = assert_deprecated(msg, ActionDispatch.deprecator) do
wrapper.show?(request)
end
assert_equal true, result
end
test "#show? emits a deprecation when show_exceptions is false" do
exception = RuntimeError.new("")
wrapper = ExceptionWrapper.new(nil, exception)
env = { "action_dispatch.show_exceptions" => false }
request = ActionDispatch::Request.new(env)
msg = "Setting action_dispatch.show_exceptions to false is deprecated. Set to :none instead."
result = assert_deprecated(msg, ActionDispatch.deprecator) do
wrapper.show?(request)
end
assert_equal false, result
end
end
end

@ -102,7 +102,7 @@ def initialize(app)
def call(env)
env["action_dispatch.permissions_policy"] = POLICY
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end
@ -194,7 +194,7 @@ def initialize(app)
def call(env)
env["action_dispatch.permissions_policy"] = POLICY
env["action_dispatch.show_exceptions"] = false
env["action_dispatch.show_exceptions"] = :none
@app.call(env)
end

@ -72,7 +72,7 @@ def teardown
with_test_routing do
output = StringIO.new
json = "[\"person]\": {\"name\": \"David\"}}"
post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => true, "action_dispatch.logger" => ActiveSupport::Logger.new(output) }
post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => :all, "action_dispatch.logger" => ActiveSupport::Logger.new(output) }
assert_response :bad_request
output.rewind && err = output.read
assert err.match?(/Error occurred while parsing request parameters/)
@ -84,7 +84,7 @@ def teardown
$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 }
post "/parse", params: json, headers: { "CONTENT_TYPE" => "application/json", "action_dispatch.show_exceptions" => :none }
end
assert_equal JSON::ParserError, exception.cause.class
assert_equal "Error occurred while parsing request parameters", exception.message

@ -38,34 +38,34 @@ def call(env)
test "skip exceptions app if not showing exceptions" do
@app = ProductionApp
assert_raise RuntimeError do
get "/", env: { "action_dispatch.show_exceptions" => false }
get "/", env: { "action_dispatch.show_exceptions" => :none }
end
end
test "rescue with error page" do
@app = ProductionApp
get "/", env: { "action_dispatch.show_exceptions" => true }
get "/", env: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_equal "500 error fixture\n", body
get "/bad_params", env: { "action_dispatch.show_exceptions" => true }
get "/bad_params", env: { "action_dispatch.show_exceptions" => :all }
assert_response 400
assert_equal "400 error fixture\n", body
get "/not_found", env: { "action_dispatch.show_exceptions" => true }
get "/not_found", env: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_equal "404 error fixture\n", body
get "/method_not_allowed", env: { "action_dispatch.show_exceptions" => true }
get "/method_not_allowed", env: { "action_dispatch.show_exceptions" => :all }
assert_response 405
assert_equal "", body
get "/unknown_http_method", env: { "action_dispatch.show_exceptions" => true }
get "/unknown_http_method", env: { "action_dispatch.show_exceptions" => :all }
assert_response 405
assert_equal "", body
get "/invalid_mimetype", headers: { "Accept" => "text/html,*", "action_dispatch.show_exceptions" => true }
get "/invalid_mimetype", headers: { "Accept" => "text/html,*", "action_dispatch.show_exceptions" => :all }
assert_response 406
assert_equal "", body
end
@ -76,11 +76,11 @@ def call(env)
begin
@app = ProductionApp
get "/", env: { "action_dispatch.show_exceptions" => true }
get "/", env: { "action_dispatch.show_exceptions" => :all }
assert_response 500
assert_equal "500 localized error fixture\n", body
get "/not_found", env: { "action_dispatch.show_exceptions" => true }
get "/not_found", env: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_equal "404 error fixture\n", body
ensure
@ -91,14 +91,14 @@ def call(env)
test "sets the HTTP charset parameter" do
@app = ProductionApp
get "/", env: { "action_dispatch.show_exceptions" => true }
get "/", env: { "action_dispatch.show_exceptions" => :all }
assert_equal "text/html; charset=utf-8", response.headers["Content-Type"]
end
test "show registered original exception for wrapped exceptions" do
@app = ProductionApp
get "/not_found_original_exception", env: { "action_dispatch.show_exceptions" => true }
get "/not_found_original_exception", env: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_match(/404 error/, body)
end
@ -112,7 +112,7 @@ def call(env)
end
@app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app)
get "/not_found_original_exception", env: { "action_dispatch.show_exceptions" => true }
get "/not_found_original_exception", env: { "action_dispatch.show_exceptions" => :all }
assert_response 404
assert_equal "YOU FAILED", body
end
@ -123,7 +123,7 @@ def call(env)
end
@app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app)
get "/method_not_allowed", env: { "action_dispatch.show_exceptions" => true }
get "/method_not_allowed", env: { "action_dispatch.show_exceptions" => :all }
assert_response 405
assert_equal "", body
end
@ -131,12 +131,12 @@ def call(env)
test "bad params exception is returned in the correct format" do
@app = ProductionApp
get "/bad_params", env: { "action_dispatch.show_exceptions" => true }
get "/bad_params", env: { "action_dispatch.show_exceptions" => :all }
assert_equal "text/html; charset=utf-8", response.headers["Content-Type"]
assert_response 400
assert_match(/400 error/, body)
get "/bad_params.json", env: { "action_dispatch.show_exceptions" => true }
get "/bad_params.json", env: { "action_dispatch.show_exceptions" => :all }
assert_equal "application/json; charset=utf-8", response.headers["Content-Type"]
assert_response 400
assert_equal("{\"status\":400,\"error\":\"Bad Request\"}", body)

@ -29,7 +29,7 @@
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false

@ -29,7 +29,7 @@
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false

@ -753,7 +753,7 @@ Notifies the logs that the request has begun. After request is complete, flushes
#### `ActionDispatch::ShowExceptions`
Rescues any exception returned by the application and renders nice exception pages if the request is local or if `config.consider_all_requests_local` is set to `true`. If `config.action_dispatch.show_exceptions` is set to `false`, exceptions will be raised regardless.
Rescues any exception returned by the application and renders nice exception pages if the request is local or if `config.consider_all_requests_local` is set to `true`. If `config.action_dispatch.show_exceptions` is set to `:none`, exceptions will be raised regardless.
#### `ActionDispatch::RequestId`

@ -29,7 +29,7 @@ Rails.application.configure do
config.cache_store = :null_store
# Raise exceptions instead of rendering exception templates.
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :rescuable
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false

@ -168,7 +168,7 @@ class MyLogger < ::Logger
add_to_config <<-RUBY
config.active_record.migration_error = :page_load
config.consider_all_requests_local = true
config.action_dispatch.show_exceptions = true
config.action_dispatch.show_exceptions = :all
RUBY
app_file "db/migrate/20140708012246_create_user.rb", <<-RUBY
@ -1491,7 +1491,7 @@ def index
test "config.action_dispatch.show_exceptions is sent in env" do
make_basic_app do |application|
application.config.action_dispatch.show_exceptions = true
application.config.action_dispatch.show_exceptions = :all
end
class ::OmgController < ActionController::Base
@ -1501,7 +1501,7 @@ def index
end
get "/"
assert_equal "true", last_response.body
assert_equal "all", last_response.body
end
test "config.action_controller.wrap_parameters is set in ActionController::Base" do

@ -60,7 +60,7 @@ def index
add_to_config "config.exceptions_app = self.routes"
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
request "/", { "REQUEST_METHOD" => "NOT_AN_HTTP_METHOD" }
assert_equal 405, last_response.status
@ -87,7 +87,7 @@ def not_acceptable
RUBY
add_to_config "config.exceptions_app = self.routes"
add_to_config "config.action_dispatch.show_exceptions = true"
add_to_config "config.action_dispatch.show_exceptions = :all"
add_to_config "config.consider_all_requests_local = false"
get "/foo", {}, { "HTTP_ACCEPT" => "invalid" }
@ -102,7 +102,7 @@ def not_acceptable
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
get "/foo"
assert_equal 404, last_response.status
@ -118,14 +118,14 @@ def index
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
get "/foo"
assert_equal 500, last_response.status
end
test "unspecified route when action_dispatch.show_exceptions is not set raises an exception" do
app.config.action_dispatch.show_exceptions = false
app.config.action_dispatch.show_exceptions = :none
assert_raise(ActionController::RoutingError) do
get "/foo"
@ -133,7 +133,7 @@ def index
end
test "unspecified route when action_dispatch.show_exceptions is set shows 404" do
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
assert_nothing_raised do
get "/foo"
@ -142,7 +142,7 @@ def index
end
test "unspecified route when action_dispatch.show_exceptions and consider_all_requests_local are set shows diagnostics" do
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
app.config.consider_all_requests_local = true
assert_nothing_raised do
@ -158,7 +158,7 @@ def index
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
app.config.consider_all_requests_local = true
get "/articles"
@ -173,7 +173,7 @@ def index
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
app.config.consider_all_requests_local = true
app_file "app/views/foo/index.html.erb", <<-ERB
@ -194,7 +194,7 @@ def index
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
app.config.consider_all_requests_local = true
get "/foo?x[y]=1&x[y][][w]=2"
@ -210,7 +210,7 @@ def index
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
app.config.consider_all_requests_local = true
limit = Rack::Utils.param_depth_limit + 1
@ -229,7 +229,7 @@ def index
end
end
RUBY
app.config.action_dispatch.show_exceptions = true
app.config.action_dispatch.show_exceptions = :all
app.config.consider_all_requests_local = true
app.config.action_dispatch.ignore_accept_header = false
@ -243,5 +243,35 @@ def index
assert_equal "text/plain", last_response.media_type
assert_match "ActiveRecord::StatementInvalid", last_response.body
end
test "show_exceptions :rescubale with a rescuable error" do
controller :foo, <<-RUBY
class FooController < ActionController::Base
def index
raise AbstractController::ActionNotFound
end
end
RUBY
app.config.action_dispatch.show_exceptions = :rescuable
get "/foo"
assert_equal 404, last_response.status
end
test "show_exceptions :rescubale with a non-rescuable error" do
controller :foo, <<-RUBY
class FooController < ActionController::Base
def index
raise 'oops'
end
end
RUBY
app.config.action_dispatch.show_exceptions = :rescuable
error = assert_raises(RuntimeError) { get "/foo" }
assert_equal "oops", error.message
end
end
end

@ -11,7 +11,7 @@ class RemoteIpTest < ActiveSupport::TestCase
def remote_ip(env = {})
remote_ip = nil
env = Rack::MockRequest.env_for("/").merge(env).merge!(
"action_dispatch.show_exceptions" => false,
"action_dispatch.show_exceptions" => :none,
"action_dispatch.key_generator" => ActiveSupport::CachingKeyGenerator.new(
ActiveSupport::KeyGenerator.new("b3c631c314c0bbca50c1b2843150fe33", iterations: 1000)
)

@ -751,7 +751,7 @@ def index
test "request to rails/welcome for api_only app is successful" do
add_to_config <<-RUBY
config.api_only = true
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :none
config.action_controller.allow_forgery_protection = true
RUBY
@ -763,7 +763,7 @@ def index
test "request to rails/welcome is successful when default_protect_from_forgery is false" do
add_to_config <<-RUBY
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :none
config.action_controller.default_protect_from_forgery = false
RUBY

@ -879,7 +879,7 @@ def test_run_in_parallel_with_unknown_object
app_file "config/environments/test.rb", <<-RUBY
Rails.application.configure do
config.action_controller.allow_forgery_protection = true
config.action_dispatch.show_exceptions = false
config.action_dispatch.show_exceptions = :none
end
RUBY

@ -269,7 +269,7 @@ def app
end
test "includes exceptions middlewares even if action_dispatch.show_exceptions is disabled" do
add_to_config "config.action_dispatch.show_exceptions = false"
add_to_config "config.action_dispatch.show_exceptions = :none"
boot!
assert_includes middleware, "ActionDispatch::ShowExceptions"
assert_includes middleware, "ActionDispatch::DebugExceptions"

@ -610,7 +610,7 @@ def call(env)
end
test "engine is a rack app and can have its own middleware stack" do
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
@plugin.write "lib/bukkits.rb", <<-RUBY
module Bukkits
@ -850,7 +850,7 @@ class MyMailer < ActionMailer::Base
end
RUBY
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
boot_rails
@ -930,7 +930,7 @@ def new
<% end %>
ERB
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
boot_rails
@ -969,7 +969,7 @@ def index
end
RUBY
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
boot_rails
@ -1258,7 +1258,7 @@ def baz
end
RUBY
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
boot_rails
@ -1414,7 +1414,7 @@ def foo
end
test "engine can be properly mounted at root" do
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
add_to_config("config.public_file_server.enabled = false")
@plugin.write "lib/bukkits.rb", <<-RUBY

@ -11,7 +11,7 @@ class ApplicationRoutingTest < ActiveSupport::TestCase
def setup
build_app
add_to_config("config.action_dispatch.show_exceptions = false")
add_to_config("config.action_dispatch.show_exceptions = :none")
@simple_plugin = engine "weblog"
@plugin = engine "blog"