class Utopia::Exceptions::Handler

A middleware which catches exceptions and performs an internal redirect.

Public Class Methods

new(app, location = '/errors/exception') click to toggle source

@param location [String] Peform an internal redirect to this location when an exception is raised.

# File lib/utopia/exceptions/handler.rb, line 28
def initialize(app, location = '/errors/exception')
        @app = app
        
        @location = location
end

Public Instance Methods

call(env) click to toggle source
# File lib/utopia/exceptions/handler.rb, line 58
def call(env)
        begin
                return @app.call(env)
        rescue Exception => exception
                log_exception(env, exception)
                
                # If the error occurred while accessing the error handler, we finish with a fatal error:
                if env[Rack::PATH_INFO] == @location
                        return fatal_error(env, exception)
                else
                        begin
                                # We do an internal redirection to the error location:
                                error_request = env.merge(Rack::PATH_INFO => @location, Rack::REQUEST_METHOD => Rack::GET)
                                error_response = @app.call(error_request)
                                
                                return [500, error_response[1], error_response[2]]
                        rescue Exception
                                # If redirection fails, we also finish with a fatal error:
                                return fatal_error(env, exception)
                        end
                end
        end
end
fatal_error(env, exception) click to toggle source

Generate a very simple fatal error response. This function should be unlikely to fail. Additionally, it generates a lowest common denominator response which should be suitable as a response to any kind of request. Ideally, this response is also not good or useful for any kind of higher level browser or API client, as this is not a normal error path but one that represents broken behaviour.

# File lib/utopia/exceptions/handler.rb, line 43
def fatal_error(env, exception)
        body = StringIO.new
        
        write_exception_to_stream(body, env, exception)
        body.rewind
        
        return [500, {HTTP::CONTENT_TYPE => "text/plain"}, body]
end
freeze() click to toggle source
Calls superclass method
# File lib/utopia/exceptions/handler.rb, line 34
def freeze
        return self if frozen?
        
        @location.freeze
        
        super
end
log_exception(env, exception) click to toggle source
# File lib/utopia/exceptions/handler.rb, line 52
def log_exception(env, exception)
        # An error has occurred, log it:
        output = env['rack.errors'] || $stderr
        write_exception_to_stream(output, env, exception, true)
end

Private Instance Methods

write_exception_to_stream(stream, env, exception, include_backtrace = false) click to toggle source
# File lib/utopia/exceptions/handler.rb, line 84
def write_exception_to_stream(stream, env, exception, include_backtrace = false)
        buffer = []
        
        buffer << "While requesting resource #{env[Rack::PATH_INFO].inspect}, a fatal error occurred:"
        
        while exception != nil
                buffer << "\t#{exception.class.name}: #{exception.to_s}"
                
                if include_backtrace
                        exception.backtrace.each do |line|
                                buffer << "\t\t#{line}"
                        end
                end
                
                exception = exception.cause
        end
        
        # We do this in one go so that lines don't get mixed up.
        stream.puts buffer.join("\n")
end