Repository: rails/rails
File: actionpack/lib/action_dispatch/middleware/show_exceptions.rb (Ruby)

Code before:
      request = ActionDispatch::Request.new env
      backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
      wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
      request.set_header "action_dispatch.exception", wrapper.unwrapped_exception
      request.set_header "action_dispatch.report_exception", !wrapper.rescue_response?

      if wrapper.show?(request)
        render_exception(wrapper.status_code, request.dup)
      else
        raise exception
      end
    end

    private
      def render_exception(status, request)
        head_request = request.head?

        request.set_header "action_dispatch.original_path", request.path_info
        request.set_header "action_dispatch.original_request_method", request.raw_request_method
        fallback_to_html_format_if_invalid_mime_type(request)
        request.path_info = "/#{status}"
        request.request_method = "GET"

        response = @exceptions_app.call(request.env)

        if response[1][Constants::X_CASCADE] == "pass" || head_request
          pass_response(status)
        else
          response
        end
      rescue Exception => failsafe_error
        $stderr.puts "Error during failsafe response: #{failsafe_error}\n  #{failsafe_error.backtrace * "\n  "}"

        [500, { Rack::CONTENT_TYPE => "text/plain; charset=utf-8" },
          ["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."]]
      end

      def fallback_to_html_format_if_invalid_mime_type(request)
        # If the MIME type for the request is invalid then the @exceptions_app may not
        # be able to handle it. To make it easier to handle, we switch to HTML.
        begin
          request.content_mime_type
        rescue ActionDispatch::Http::MimeNegotiation::InvalidType
          request.set_header "CONTENT_TYPE", "text/html"
        end

        begin
          request.formats

Review comment (refactor):
I think this should belong in the PublicException app, otherwise we'd be discarding custom headers sent by a custom PublicException app (We'd just send the X_CASCADE header).

Another small benefit if we move this in the PublicException app is that we won't need to render the template since we don't need it.

The downside is that application will have to implement this in their PublicException app if they use a custom one.

Code after:
      request = ActionDispatch::Request.new env
      backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
      wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
      request.set_header "action_dispatch.exception", wrapper.unwrapped_exception
      request.set_header "action_dispatch.report_exception", !wrapper.rescue_response?

      if wrapper.show?(request)
        render_exception(request.dup, wrapper)
      else
        raise exception
      end
    end

    private
      def render_exception(request, wrapper)
        status = wrapper.status_code
        request.set_header "action_dispatch.original_path", request.path_info
        request.set_header "action_dispatch.original_request_method", request.raw_request_method
        fallback_to_html_format_if_invalid_mime_type(request)
        request.path_info = "/#{status}"
        request.request_method = "GET"
        response = @exceptions_app.call(request.env)
        response[1][Constants::X_CASCADE] == "pass" ? pass_response(status) : response
      rescue Exception => failsafe_error
        $stderr.puts "Error during failsafe response: #{failsafe_error}\n  #{failsafe_error.backtrace * "\n  "}"

        [500, { Rack::CONTENT_TYPE => "text/plain; charset=utf-8" },
          ["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."]]
      end

      def fallback_to_html_format_if_invalid_mime_type(request)
        # If the MIME type for the request is invalid then the @exceptions_app may not
        # be able to handle it. To make it easier to handle, we switch to HTML.
        begin
          request.content_mime_type
        rescue ActionDispatch::Http::MimeNegotiation::InvalidType
          request.set_header "CONTENT_TYPE", "text/html"
        end

        begin
          request.formats
        rescue ActionDispatch::Http::MimeNegotiation::InvalidType
          request.set_header "HTTP_ACCEPT", "text/html"
        end
      end

      def pass_response(status)
        [status, { Rack::CONTENT_TYPE => "text/html; charset=#{Response.default_charset}",