diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/middleware/debug_exceptions.rb')
-rw-r--r-- | actionpack/lib/action_dispatch/middleware/debug_exceptions.rb | 225 |
1 files changed, 121 insertions, 104 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index b55c937e0c..ee644f41c8 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -1,16 +1,16 @@ -require 'action_dispatch/http/request' -require 'action_dispatch/middleware/exception_wrapper' -require 'action_dispatch/routing/inspector' -require 'action_view' -require 'action_view/base' +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' +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', __FILE__) + RESCUES_TEMPLATE_PATH = File.expand_path("../templates", __FILE__) class DebugView < ActionView::Base def debug_params(params) @@ -19,7 +19,7 @@ module ActionDispatch clean_params.delete("controller") if clean_params.empty? - 'None' + "None" else PP.pp(clean_params, "", 200) end @@ -27,15 +27,23 @@ module ActionDispatch def debug_headers(headers) if headers.present? - headers.inspect.gsub(',', ",\n") + headers.inspect.gsub(",", ",\n") else - 'None' + "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(*) + if logger = ActionView::Base.logger + logger.silence { super } + else + super + end + end end def initialize(app, routes_app = nil, response_format = :default) @@ -48,7 +56,7 @@ module ActionDispatch request = ActionDispatch::Request.new env _, headers, body = response = @app.call(env) - if headers['X-Cascade'] == 'pass' + if headers["X-Cascade"] == "pass" body.close if body.respond_to?(:close) raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}" end @@ -61,120 +69,129 @@ module ActionDispatch private - def render_exception(request, exception) - backtrace_cleaner = request.get_header('action_dispatch.backtrace_cleaner') - wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) - log_error(request, wrapper) - - if request.get_header('action_dispatch.show_detailed_exceptions') - case @response_format - when :api - render_for_api_application(request, wrapper) - when :default - render_for_default_application(request, wrapper) + def render_exception(request, exception) + backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner") + wrapper = ExceptionWrapper.new(backtrace_cleaner, exception) + log_error(request, wrapper) + + if request.get_header("action_dispatch.show_detailed_exceptions") + content_type = request.formats.first + + if api_request?(content_type) + render_for_api_request(content_type, wrapper) + else + render_for_browser_request(request, wrapper) + end + else + raise exception end - else - raise exception end - end - def render_for_default_application(request, wrapper) - template = create_template(request, wrapper) - file = "rescues/#{wrapper.rescue_template}" + def render_for_browser_request(request, wrapper) + template = create_template(request, wrapper) + file = "rescues/#{wrapper.rescue_template}" - if request.xhr? - body = template.render(template: file, layout: false, formats: [:text]) - format = "text/plain" - else - body = template.render(template: file, layout: 'rescues/layout') - format = "text/html" + if request.xhr? + body = template.render(template: file, layout: false, formats: [:text]) + format = "text/plain" + else + body = template.render(template: file, layout: "rescues/layout") + format = "text/html" + end + render(wrapper.status_code, body, format) end - render(wrapper.status_code, body, format) - end - def render_for_api_application(request, wrapper) - body = { - status: wrapper.status_code, - error: Rack::Utils::HTTP_STATUS_CODES.fetch( - wrapper.status_code, - Rack::Utils::HTTP_STATUS_CODES[500] - ), - exception: wrapper.exception.inspect, - traces: wrapper.traces - } - - content_type = request.formats.first - to_format = "to_#{content_type.to_sym}" - - if content_type && body.respond_to?(to_format) - formatted_body = body.public_send(to_format) - format = content_type - else - formatted_body = body.to_json - format = Mime[:json] - end - - render(wrapper.status_code, formatted_body, format) - end + def render_for_api_request(content_type, wrapper) + body = { + status: wrapper.status_code, + error: Rack::Utils::HTTP_STATUS_CODES.fetch( + wrapper.status_code, + Rack::Utils::HTTP_STATUS_CODES[500] + ), + exception: wrapper.exception.inspect, + traces: wrapper.traces + } + + to_format = "to_#{content_type.to_sym}" + + if content_type && body.respond_to?(to_format) + formatted_body = body.public_send(to_format) + format = content_type + else + formatted_body = body.to_json + format = Mime[:json] + end + + render(wrapper.status_code, formatted_body, format) + end - def create_template(request, wrapper) - traces = wrapper.traces + def create_template(request, wrapper) + traces = wrapper.traces - trace_to_show = 'Application Trace' - if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error' - trace_to_show = 'Full Trace' + trace_to_show = "Application Trace" + if traces[trace_to_show].empty? && wrapper.rescue_template != "routing_error" + trace_to_show = "Full Trace" + end + + if source_to_show = traces[trace_to_show].first + source_to_show_id = source_to_show[:id] + end + + DebugView.new([RESCUES_TEMPLATE_PATH], + request: request, + exception: wrapper.exception, + traces: traces, + show_source_idx: source_to_show_id, + trace_to_show: trace_to_show, + routes_inspector: routes_inspector(wrapper.exception), + source_extracts: wrapper.source_extracts, + line_number: wrapper.line_number, + file: wrapper.file + ) end - if source_to_show = traces[trace_to_show].first - source_to_show_id = source_to_show[:id] + def render(status, body, format) + [status, { "Content-Type" => "#{format}; charset=#{Response.default_charset}", "Content-Length" => body.bytesize.to_s }, [body]] end - DebugView.new([RESCUES_TEMPLATE_PATH], - request: request, - exception: wrapper.exception, - traces: traces, - show_source_idx: source_to_show_id, - trace_to_show: trace_to_show, - routes_inspector: routes_inspector(wrapper.exception), - source_extracts: wrapper.source_extracts, - line_number: wrapper.line_number, - file: wrapper.file - ) - end + def log_error(request, wrapper) + logger = logger(request) + return unless logger - def render(status, body, format) - [status, {'Content-Type' => "#{format}; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]] - end + exception = wrapper.exception - def log_error(request, wrapper) - logger = logger(request) - return unless logger + trace = wrapper.application_trace + trace = wrapper.framework_trace if trace.empty? - exception = wrapper.exception + ActiveSupport::Deprecation.silence do + logger.fatal " " + logger.fatal "#{exception.class} (#{exception.message}):" + log_array logger, exception.annoted_source_code if exception.respond_to?(:annoted_source_code) + logger.fatal " " + log_array logger, trace + end + end - trace = wrapper.application_trace - trace = wrapper.framework_trace if trace.empty? + def log_array(logger, array) + array.map { |line| logger.fatal line } + end - ActiveSupport::Deprecation.silence do - message = "\n#{exception.class} (#{exception.message}):\n" - message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code) - message << " " << trace.join("\n ") - logger.fatal("#{message}\n\n") + def logger(request) + request.logger || ActionView::Base.logger || stderr_logger end - end - def logger(request) - request.logger || stderr_logger - end + def stderr_logger + @stderr_logger ||= ActiveSupport::Logger.new($stderr) + end - def stderr_logger - @stderr_logger ||= ActiveSupport::Logger.new($stderr) - end + def routes_inspector(exception) + if @routes_app.respond_to?(:routes) && (exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)) + ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes) + end + end - def routes_inspector(exception) - if @routes_app.respond_to?(:routes) && (exception.is_a?(ActionController::RoutingError) || exception.is_a?(ActionView::Template::Error)) - ActionDispatch::Routing::RoutesInspector.new(@routes_app.routes.routes) + def api_request?(content_type) + @response_format == :api && !content_type.html? end - end end end |