class Sinatra::ShowExceptions
Sinatra::ShowExceptions
catches all exceptions raised from the app it wraps. It shows a useful backtrace with the sourcefile and clickable context, the whole Rack
environment and the request data.
Be careful when you use this on public-facing sites as it could reveal information helpful to attackers.
Public Class Methods
new(app)
click to toggle source
# File lib/sinatra/show_exceptions.rb 17 def initialize(app) 18 @app = app 19 end
Public Instance Methods
call(env)
click to toggle source
# File lib/sinatra/show_exceptions.rb 21 def call(env) 22 @app.call(env) 23 rescue Exception => e 24 errors, env["rack.errors"] = env["rack.errors"], @@eats_errors 25 26 if prefers_plain_text?(env) 27 content_type = "text/plain" 28 body = dump_exception(e) 29 else 30 content_type = "text/html" 31 body = pretty(env, e) 32 end 33 34 env["rack.errors"] = errors 35 36 [ 37 500, 38 { 39 "Content-Type" => content_type, 40 "Content-Length" => body.bytesize.to_s 41 }, 42 [body] 43 ] 44 end
pretty(env, exception)
click to toggle source
Pulled from Rack::ShowExceptions in order to override TEMPLATE. If Rack
provides another way to override, this could be removed in the future.
# File lib/sinatra/show_exceptions.rb 49 def pretty(env, exception) 50 req = Rack::Request.new(env) 51 52 # This double assignment is to prevent an "unused variable" warning on 53 # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me. 54 path = path = (req.script_name + req.path_info).squeeze("/") 55 56 # This double assignment is to prevent an "unused variable" warning on 57 # Ruby 1.9.3. Yes, it is dumb, but I don't like Ruby yelling at me. 58 frames = frames = exception.backtrace.map { |line| 59 frame = OpenStruct.new 60 if line =~ /(.*?):(\d+)(:in `(.*)')?/ 61 frame.filename = $1 62 frame.lineno = $2.to_i 63 frame.function = $4 64 65 begin 66 lineno = frame.lineno-1 67 lines = ::File.readlines(frame.filename) 68 frame.pre_context_lineno = [lineno-CONTEXT, 0].max 69 frame.pre_context = lines[frame.pre_context_lineno...lineno] 70 frame.context_line = lines[lineno].chomp 71 frame.post_context_lineno = [lineno+CONTEXT, lines.size].min 72 frame.post_context = lines[lineno+1..frame.post_context_lineno] 73 rescue 74 end 75 76 frame 77 else 78 nil 79 end 80 }.compact 81 82 TEMPLATE.result(binding) 83 end
Private Instance Methods
bad_request?(e)
click to toggle source
# File lib/sinatra/show_exceptions.rb 87 def bad_request?(e) 88 Sinatra::BadRequest === e 89 end
frame_class(frame)
click to toggle source
# File lib/sinatra/show_exceptions.rb 96 def frame_class(frame) 97 if frame.filename =~ %r{lib/sinatra.*\.rb} 98 "framework" 99 elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) || 100 frame.filename =~ %r{/bin/(\w+)\z} 101 "system" 102 else 103 "app" 104 end 105 end
prefers_plain_text?(env)
click to toggle source
# File lib/sinatra/show_exceptions.rb 91 def prefers_plain_text?(env) 92 !(Request.new(env).preferred_type("text/plain","text/html") == "text/html") && 93 [/curl/].index { |item| item =~ env["HTTP_USER_AGENT"] } 94 end