aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/lib/action_dispatch/middleware/failsafe.rb
blob: 836098482c007a5cc1fc2f7ba6a45a7bbcfcdf79 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
                     











                                                                           
                                           
















                                                                        
                                 
            
                                                                          









                                                                                           
                                          
                      





                             
module ActionDispatch
  class Failsafe
    cattr_accessor :error_file_path
    self.error_file_path = Rails.public_path if defined?(Rails.public_path)

    def initialize(app)
      @app = app
    end

    def call(env)
      @app.call(env)
    rescue Exception => exception
      # Reraise exception in test environment
      if defined?(Rails) && Rails.env.test?
        raise exception
      else
        failsafe_response(exception)
      end
    end

    private
      def failsafe_response(exception)
        log_failsafe_exception(exception)
        [500, {'Content-Type' => 'text/html'}, failsafe_response_body]
      rescue Exception => failsafe_error # Logger or IO errors
        $stderr.puts "Error during failsafe response: #{failsafe_error}"
      end

      def failsafe_response_body
        error_path = "#{self.class.error_file_path}/500.html"
        if File.exist?(error_path)
          [File.read(error_path)]
        else
          ["<html><body><h1>500 Internal Server Error</h1></body></html>"]
        end
      end

      def log_failsafe_exception(exception)
        message = "/!\\ FAILSAFE /!\\  #{Time.now}\n  Status: 500 Internal Server Error\n"
        message << "  #{exception}\n    #{exception.backtrace.join("\n    ")}" if exception
        failsafe_logger.fatal(message)
      end

      def failsafe_logger
        if defined?(Rails) && Rails.logger
          Rails.logger
        else
          Logger.new($stderr)
        end
      end
  end
end