class BetterErrors::Middleware

Better Errors' error handling middleware. Including this in your middleware stack will show a Better Errors error page for exceptions raised below this middleware.

If you are using Ruby on Rails, you do not need to manually insert this middleware into your middleware stack.

@example Sinatra

require "better_errors"

if development?
  use BetterErrors::Middleware
end

@example Rack

require "better_errors"
if ENV["RACK_ENV"] == "development"
  use BetterErrors::Middleware
end

Constants

ALLOWED_IPS

The set of IP addresses that are allowed to access Better Errors.

Set to `{ “127.0.0.1/8”, “::1/128” }` by default.

Public Class Methods

allow_ip!(addr) click to toggle source

Adds an address to the set of IP addresses allowed to access Better Errors.

# File lib/better_errors/middleware.rb, line 35
def self.allow_ip!(addr)
  ALLOWED_IPS << IPAddr.new(addr)
end
new(app, handler = ErrorPage) click to toggle source

A new instance of BetterErrors::Middleware

@param app The Rack app/middleware to wrap with Better Errors @param handler The error handler to use.

# File lib/better_errors/middleware.rb, line 46
def initialize(app, handler = ErrorPage)
  @app      = app
  @handler  = handler
end

Public Instance Methods

call(env) click to toggle source

Calls the Better Errors middleware

@param [Hash] env @return [Array]

# File lib/better_errors/middleware.rb, line 55
def call(env)
  if allow_ip? env
    better_errors_call env
  else
    @app.call env
  end
end

Private Instance Methods

allow_ip?(env) click to toggle source
# File lib/better_errors/middleware.rb, line 65
def allow_ip?(env)
  request = Rack::Request.new(env)
  return true unless request.ip and !request.ip.strip.empty?
  ip = IPAddr.new request.ip.split("%").first
  ALLOWED_IPS.any? { |subnet| subnet.include? ip }
end
better_errors_call(env) click to toggle source
# File lib/better_errors/middleware.rb, line 72
def better_errors_call(env)
  case env["PATH_INFO"]
  when %r{/__better_errors/(?<id>.+?)/(?<method>\w+)\z}
    internal_call env, $~
  when %r{/__better_errors/?\z}
    show_error_page env
  else
    protected_app_call env
  end
end
internal_call(env, opts) click to toggle source
# File lib/better_errors/middleware.rb, line 126
def internal_call(env, opts)
  if opts[:id] != @error_page.id
    return [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(error: "Session expired")]]
  end

  env["rack.input"].rewind
  response = @error_page.send("do_#{opts[:method]}", JSON.parse(env["rack.input"].read))
  [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(response)]]
end
log_exception() click to toggle source
# File lib/better_errors/middleware.rb, line 115
def log_exception
  return unless BetterErrors.logger

  message = "\n#{@error_page.exception_type} - #{@error_page.exception_message}:\n"
  @error_page.backtrace_frames.each do |frame|
    message << "  #{frame}\n"
  end

  BetterErrors.logger.fatal message
end
no_errors_page() click to toggle source
# File lib/better_errors/middleware.rb, line 136
def no_errors_page
  "<h1>No errors</h1><p>No errors have been recorded yet.</p><hr>" +
  "<code>Better Errors v#{BetterErrors::VERSION}</code>"
end
protected_app_call(env) click to toggle source
# File lib/better_errors/middleware.rb, line 83
def protected_app_call(env)
  @app.call env
rescue Exception => ex
  @error_page = @handler.new ex, env
  log_exception
  show_error_page(env, ex)
end
show_error_page(env, exception=nil) click to toggle source
# File lib/better_errors/middleware.rb, line 91
def show_error_page(env, exception=nil)
  type, content = if @error_page
    if text?(env)
      [ 'plain', @error_page.render('text') ]
    else
      [ 'html', @error_page.render ]
    end
  else
    [ 'html', no_errors_page ]
  end

  status_code = 500
  if defined? ActionDispatch::ExceptionWrapper
    status_code = ActionDispatch::ExceptionWrapper.new(env, exception).status_code
  end

  [status_code, { "Content-Type" => "text/#{type}; charset=utf-8" }, [content]]
end
text?(env) click to toggle source
# File lib/better_errors/middleware.rb, line 110
def text?(env)
  env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ||
  !env["HTTP_ACCEPT"].to_s.include?('html')
end