7 # Rack::ShowExceptions catches all exceptions raised from the app it
8 # wraps. It shows a useful backtrace with the sourcefile and
9 # clickable context, the whole Rack environment and the request
12 # Be careful when you use this on public-facing sites as it could
13 # reveal information helpful to attackers.
20 @template = ERB
.new(TEMPLATE
)
25 rescue StandardError
, LoadError
, SyntaxError
=> e
26 backtrace
= pretty(env, e
)
28 {"Content-Type" => "text/html",
29 "Content-Length" => backtrace
.join
.size
.to_s
},
33 def pretty(env, exception
)
34 req
= Rack
::Request.new(env)
35 path
= (req
.script_name
+ req
.path_info
).squeeze("/")
37 frames
= exception
.backtrace
.map
{ |line
|
38 frame
= OpenStruct
.new
39 if line
=~
/(.*?):(\d+)(:in `(.*)')?/
41 frame
.lineno
= $2.to_i
45 lineno
= frame
.lineno-1
46 lines
= ::File.readlines(frame
.filename
)
47 frame
.pre_context_lineno
= [lineno-CONTEXT
, 0].max
48 frame
.pre_context
= lines
[frame
.pre_context_lineno
...lineno
]
49 frame
.context_line
= lines
[lineno
].chomp
50 frame
.post_context_lineno
= [lineno
+CONTEXT
, lines
.size
].min
51 frame
.post_context
= lines
[lineno
+1..frame
.post_context_lineno
]
61 env["rack.errors"].puts
"#{exception.class}: #{exception.message}"
62 env["rack.errors"].puts exception
.backtrace
.map
{ |l
| "\t" + l
}
63 env["rack.errors"].flush
65 [@template.result(binding
)]
71 Utils
.escape_html(obj
)
73 Utils
.escape_html(obj
.inspect
)
79 # adapted from Django <djangoproject.com>
80 # Copyright (c) 2005, the Lawrence Journal-World
81 # Used under the modified BSD license:
82 # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
84 <!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
87 <meta http-equiv
="content-type" content
="text/html; charset=utf-8" />
88 <meta name
="robots" content
="NONE,NOARCHIVE" />
89 <title
><%=h exception
.class %> at
<%=h path
%></title
>
90 <style type
="text/css">
91 html
* { padding
:0; margin
:0; }
92 body
* { padding
:10px 20px
; }
93 body
* * { padding
:0; }
94 body
{ font
:small sans-serif
; }
95 body
>div
{ border-bottom
:1px solid
#ddd; }
96 h1
{ font-weight
:normal; }
97 h2
{ margin-bottom
:.8em
; }
98 h2 span
{ font-size
:80%; color
:#666; font-weight:normal; }
99 h3
{ margin
:1em 0 .5em
0; }
100 h4
{ margin
:0 0 .5em
0; font-weight
: normal
; }
102 border
:1px solid
#ccc; border-collapse: collapse; background:white; }
103 tbody td
, tbody th
{ vertical-align
:top; padding
:2px 3px
; }
105 padding
:1px 6px
1px
3px
; background
:#fefefe; text-align:left;
106 font-weight
:normal; font-size
:11px; border
:1px solid
#ddd; }
107 tbody th
{ text-align
:right; color
:#666; padding-right:.5em; }
108 table
.vars
{ margin
:5px 0 2px
40px
; }
109 table
.vars td
, table
.req td
{ font-family
:monospace; }
110 table td
.code
{ width
:100%;}
111 table td
.code div
{ overflow
:hidden; }
112 table
.source th
{ color
:#666; }
114 font-family
:monospace; white-space
:pre; border-bottom
:1px solid
#eee; }
115 ul
.traceback
{ list-style-type
:none; }
116 ul
.traceback li
.frame
{ margin-bottom
:1em; }
117 div
.context
{ margin
: 10px
0; }
119 padding-left
:30px; margin
:0 10px
; list-style-position
: inside
; }
121 font-family
:monospace; white-space
:pre; color
:#666; cursor:pointer; }
122 div
.context ol
.context-line li
{ color
:black; background-color
:#ccc; }
123 div
.context ol
.context-line li span
{ float
: right
; }
124 div
.commands
{ margin-left
: 40px
; }
125 div
.commands a
{ color
:black; text-decoration
:none; }
126 #summary { background: #ffc; }
127 #summary h2 { font-weight: normal; color: #666; }
128 #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; }
129 #summary ul#quicklinks li { float: left; padding: 0 1em; }
130 #summary ul#quicklinks>li+li { border-left: 1px #666 solid; }
131 #explanation { background:#eee; }
132 #template, #template-not-exist { background:#f6f6f6; }
133 #template-not-exist ul { margin: 0 0 0 20px; }
134 #traceback { background:#eee; }
135 #requestinfo { background:#f6f6f6; padding-left:120px; }
136 #summary table { border:none; background:transparent; }
137 #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
138 #requestinfo h3 { margin-bottom:-1em; }
139 .error
{ background
: #ffc; }
140 .specific
{ color
:#cc3300; font-weight:bold; }
142 <script type
="text/javascript">
144 function
getElementsByClassName(oElm
, strTagName
, strClassName
){
145 // Written by Jonathan Snook
, http
://www
.snook
.ca
/jon
;
146 // Add-ons by Robert Nyman
, http
://www
.robertnyman
.com
147 var arrElements
= (strTagName
== "*" && document
.all
)? document
.all
:
148 oElm
.getElementsByTagName(strTagName
);
149 var arrReturnElements
= new
Array();
150 strClassName
= strClassName
.replace(/\-/g
, "\\-");
151 var oRegExp
= new
RegExp("(^|\\s)" + strClassName
+ "(\\s|$$)");
153 for(var i
=0; i
<arrElements
.length
; i
++){
154 oElement
= arrElements
[i
];
155 if(oRegExp
.test(oElement
.className
)){
156 arrReturnElements
.push(oElement
);
159 return (arrReturnElements
)
161 function
hideAll(elems
) {
162 for (var e
= 0; e
< elems
.length
; e
++) {
163 elems
[e
].style
.display
= 'none';
166 window
.onload
= function() {
167 hideAll(getElementsByClassName(document
, 'table', 'vars'));
168 hideAll(getElementsByClassName(document
, 'ol', 'pre-context'));
169 hideAll(getElementsByClassName(document
, 'ol', 'post-context'));
172 for (var i
= 0; i
< arguments
.length
; i
++) {
173 var e
= document
.getElementById(arguments
[i
]);
175 e
.style
.display
= e
.style
.display
== 'none' ? 'block' : 'none';
180 function
varToggle(link
, id
) {
182 var s
= link
.getElementsByTagName('span')[0];
183 var uarr
= String
.fromCharCode(0x25b6);
184 var darr
= String
.fromCharCode(0x25bc);
185 s
.innerHTML
= s
.innerHTML
== uarr
? darr
: uarr
;
194 <h1
><%=h exception
.class %> at
<%=h path
%></h1
>
195 <h2
><%=h exception
.message
%></h2
>
198 <td
><code
><%=h frames
.first
.filename
%></code>: in <code><%=h frames.first.function %></code
>, line
<%=h frames
.first
.lineno
%></td
>
201 <td
><code
><%=h req
.request_method
%> <%=h(req
.host
+ path
)%></code></td
>
206 <li
><a href
="#get-info">GET
</a></li
>
207 <li
><a href
="#post-info">POST
</a></li
>
208 <li
><a href
="#cookie-info">Cookies
</a></li
>
209 <li
><a href
="#env-info">ENV</a></li
>
214 <h2
>Traceback
<span
>(innermost first
)</span></h2
>
215 <ul
class="traceback">
216 <% frames
.each
{ |frame
| %>
218 <code
><%=h frame
.filename
%></code>: in <code><%=h frame.function %></code
>
220 <% if frame
.context_line
%>
221 <div
class="context" id
="c<%=h frame.object_id %>">
222 <% if frame
.pre_context
%>
223 <ol start
="<%=h frame.pre_context_lineno+1 %>" class="pre-context" id
="pre<%=h frame.object_id %>">
224 <% frame
.pre_context
.each
{ |line
| %>
225 <li onclick
="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line
%></li
>
230 <ol start
="<%=h frame.lineno %>" class="context-line">
231 <li onclick
="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h frame
.context_line
%><span
>...</span></li
></ol
>
233 <% if frame
.post_context
%>
234 <ol start
='<%=h frame.lineno+1 %>' class="post-context" id
="post<%=h frame.object_id %>">
235 <% frame
.post_context
.each
{ |line
| %>
236 <li onclick
="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line
%></li
>
247 <div id
="requestinfo">
248 <h2
>Request information
</h2
>
250 <h3 id
="get-info">GET
</h3
>
251 <% unless req
.GET
.empty
? %>
260 <% req
.GET
.sort_by
{ |k
, v
| k
.to_s
}.each
{ |key
, val
| %>
263 <td
class="code"><div
><%=h val
.inspect
%></div></td
>
272 <h3 id
="post-info">POST
</h3
>
273 <% unless req
.POST
.empty
? %>
282 <% req
.POST
.sort_by
{ |k
, v
| k
.to_s
}.each
{ |key
, val
| %>
285 <td
class="code"><div
><%=h val
.inspect
%></div></td
>
295 <h3 id
="cookie-info">COOKIES
</h3
>
296 <% unless req
.cookies
.empty
? %>
305 <% req
.cookies
.each
{ |key
, val
| %>
308 <td
class="code"><div
><%=h val
.inspect
%></div></td
>
314 <p
>No cookie
data.</p
>
317 <h3 id
="env-info">Rack
ENV</h3
>
326 <% env.sort_by
{ |k
, v
| k
.to_s
}.each
{ |key
, val
| %>
329 <td
class="code"><div
><%=h val
%></div></td
>
337 <div id
="explanation">
339 You
're seeing this error because you use <code>Rack::ShowExceptions</code>.