mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
ef40fb6fd8
There are two cases where the debug view does not show the error details properly: * When the cause is mapped to an HTTP status code the last exception is unexpectedly uwrapped * When the last error is thrown from a view template the debug view is not using the `rescues/template_error.html.erb` to generate the view Both the cases could be fixed by not unwrapping the exception. The only case where the exception should be unwrapped is when the last error is an `ActionView::Template::Error` object. In this case the HTTP status code is determined based on the cause. There are actually more wrapper exceptions that are intentionally thrown. However, there is a consistent pattern of setting the original message and original backtrace to the wrapper exception implemented, so the debug view will not lose the information about what went wrong eariler.
62 lines
2.4 KiB
Ruby
62 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "action_dispatch/http/request"
|
|
require "action_dispatch/middleware/exception_wrapper"
|
|
|
|
module ActionDispatch
|
|
# This middleware rescues any exception returned by the application
|
|
# and calls an exceptions app that will wrap it in a format for the end user.
|
|
#
|
|
# The exceptions app should be passed as parameter on initialization
|
|
# of ShowExceptions. Every time there is an exception, ShowExceptions will
|
|
# store the exception in env["action_dispatch.exception"], rewrite the
|
|
# PATH_INFO to the exception status code and call the Rack app.
|
|
#
|
|
# If the application returns a "X-Cascade" pass response, this middleware
|
|
# will send an empty response as result with the correct status code.
|
|
# If any exception happens inside the exceptions app, this middleware
|
|
# catches the exceptions and returns a FAILSAFE_RESPONSE.
|
|
class ShowExceptions
|
|
FAILSAFE_RESPONSE = [500, { "Content-Type" => "text/plain" },
|
|
["500 Internal Server Error\n" \
|
|
"If you are the administrator of this website, then please read this web " \
|
|
"application's log file and/or the web server's log file to find out what " \
|
|
"went wrong."]]
|
|
|
|
def initialize(app, exceptions_app)
|
|
@app = app
|
|
@exceptions_app = exceptions_app
|
|
end
|
|
|
|
def call(env)
|
|
request = ActionDispatch::Request.new env
|
|
@app.call(env)
|
|
rescue Exception => exception
|
|
if request.show_exceptions?
|
|
render_exception(request, exception)
|
|
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
|
|
request.set_header "action_dispatch.exception", wrapper.unwrapped_exception
|
|
request.set_header "action_dispatch.original_path", request.path_info
|
|
request.path_info = "/#{status}"
|
|
response = @exceptions_app.call(request.env)
|
|
response[1]["X-Cascade"] == "pass" ? pass_response(status) : response
|
|
rescue Exception => failsafe_error
|
|
$stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
|
|
FAILSAFE_RESPONSE
|
|
end
|
|
|
|
def pass_response(status)
|
|
[status, { "Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0" }, []]
|
|
end
|
|
end
|
|
end
|