diff options
author | Joshua Peek <josh@joshpeek.com> | 2009-04-14 15:52:23 -0500 |
---|---|---|
committer | Joshua Peek <josh@joshpeek.com> | 2009-04-14 15:52:23 -0500 |
commit | 4839fe2e8201835a53ab6c75528a613e8bf25bfb (patch) | |
tree | 55f5c3f76358fcbb28fca6ac9bcd915cbefac89a /actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb | |
parent | 1120aaceae95b95ef491ca226154500051b5fe38 (diff) | |
download | rails-4839fe2e8201835a53ab6c75528a613e8bf25bfb.tar.gz rails-4839fe2e8201835a53ab6c75528a613e8bf25bfb.tar.bz2 rails-4839fe2e8201835a53ab6c75528a613e8bf25bfb.zip |
Move bundled rack into ActionDispatch
Diffstat (limited to 'actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb')
-rw-r--r-- | actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb new file mode 100644 index 0000000000..697bc41fdb --- /dev/null +++ b/actionpack/lib/action_dispatch/vendor/rack-1.0/rack/showexceptions.rb @@ -0,0 +1,349 @@ +require 'ostruct' +require 'erb' +require 'rack/request' +require 'rack/utils' + +module Rack + # Rack::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. + + class ShowExceptions + CONTEXT = 7 + + def initialize(app) + @app = app + @template = ERB.new(TEMPLATE) + end + + def call(env) + @app.call(env) + rescue StandardError, LoadError, SyntaxError => e + backtrace = pretty(env, e) + [500, + {"Content-Type" => "text/html", + "Content-Length" => backtrace.join.size.to_s}, + backtrace] + end + + def pretty(env, exception) + req = Rack::Request.new(env) + path = (req.script_name + req.path_info).squeeze("/") + + frames = exception.backtrace.map { |line| + frame = OpenStruct.new + if line =~ /(.*?):(\d+)(:in `(.*)')?/ + frame.filename = $1 + frame.lineno = $2.to_i + frame.function = $4 + + begin + lineno = frame.lineno-1 + lines = ::File.readlines(frame.filename) + frame.pre_context_lineno = [lineno-CONTEXT, 0].max + frame.pre_context = lines[frame.pre_context_lineno...lineno] + frame.context_line = lines[lineno].chomp + frame.post_context_lineno = [lineno+CONTEXT, lines.size].min + frame.post_context = lines[lineno+1..frame.post_context_lineno] + rescue + end + + frame + else + nil + end + }.compact + + env["rack.errors"].puts "#{exception.class}: #{exception.message}" + env["rack.errors"].puts exception.backtrace.map { |l| "\t" + l } + env["rack.errors"].flush + + [@template.result(binding)] + end + + def h(obj) # :nodoc: + case obj + when String + Utils.escape_html(obj) + else + Utils.escape_html(obj.inspect) + end + end + + # :stopdoc: + +# adapted from Django <djangoproject.com> +# Copyright (c) 2005, the Lawrence Journal-World +# Used under the modified BSD license: +# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5 +TEMPLATE = <<'HTML' +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="en"> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8" /> + <meta name="robots" content="NONE,NOARCHIVE" /> + <title><%=h exception.class %> at <%=h path %></title> + <style type="text/css"> + html * { padding:0; margin:0; } + body * { padding:10px 20px; } + body * * { padding:0; } + body { font:small sans-serif; } + body>div { border-bottom:1px solid #ddd; } + h1 { font-weight:normal; } + h2 { margin-bottom:.8em; } + h2 span { font-size:80%; color:#666; font-weight:normal; } + h3 { margin:1em 0 .5em 0; } + h4 { margin:0 0 .5em 0; font-weight: normal; } + table { + border:1px solid #ccc; border-collapse: collapse; background:white; } + tbody td, tbody th { vertical-align:top; padding:2px 3px; } + thead th { + padding:1px 6px 1px 3px; background:#fefefe; text-align:left; + font-weight:normal; font-size:11px; border:1px solid #ddd; } + tbody th { text-align:right; color:#666; padding-right:.5em; } + table.vars { margin:5px 0 2px 40px; } + table.vars td, table.req td { font-family:monospace; } + table td.code { width:100%;} + table td.code div { overflow:hidden; } + table.source th { color:#666; } + table.source td { + font-family:monospace; white-space:pre; border-bottom:1px solid #eee; } + ul.traceback { list-style-type:none; } + ul.traceback li.frame { margin-bottom:1em; } + div.context { margin: 10px 0; } + div.context ol { + padding-left:30px; margin:0 10px; list-style-position: inside; } + div.context ol li { + font-family:monospace; white-space:pre; color:#666; cursor:pointer; } + div.context ol.context-line li { color:black; background-color:#ccc; } + div.context ol.context-line li span { float: right; } + div.commands { margin-left: 40px; } + div.commands a { color:black; text-decoration:none; } + #summary { background: #ffc; } + #summary h2 { font-weight: normal; color: #666; } + #summary ul#quicklinks { list-style-type: none; margin-bottom: 2em; } + #summary ul#quicklinks li { float: left; padding: 0 1em; } + #summary ul#quicklinks>li+li { border-left: 1px #666 solid; } + #explanation { background:#eee; } + #template, #template-not-exist { background:#f6f6f6; } + #template-not-exist ul { margin: 0 0 0 20px; } + #traceback { background:#eee; } + #requestinfo { background:#f6f6f6; padding-left:120px; } + #summary table { border:none; background:transparent; } + #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; } + #requestinfo h3 { margin-bottom:-1em; } + .error { background: #ffc; } + .specific { color:#cc3300; font-weight:bold; } + </style> + <script type="text/javascript"> + //<!-- + function getElementsByClassName(oElm, strTagName, strClassName){ + // Written by Jonathan Snook, http://www.snook.ca/jon; + // Add-ons by Robert Nyman, http://www.robertnyman.com + var arrElements = (strTagName == "*" && document.all)? document.all : + oElm.getElementsByTagName(strTagName); + var arrReturnElements = new Array(); + strClassName = strClassName.replace(/\-/g, "\\-"); + var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)"); + var oElement; + for(var i=0; i<arrElements.length; i++){ + oElement = arrElements[i]; + if(oRegExp.test(oElement.className)){ + arrReturnElements.push(oElement); + } + } + return (arrReturnElements) + } + function hideAll(elems) { + for (var e = 0; e < elems.length; e++) { + elems[e].style.display = 'none'; + } + } + window.onload = function() { + hideAll(getElementsByClassName(document, 'table', 'vars')); + hideAll(getElementsByClassName(document, 'ol', 'pre-context')); + hideAll(getElementsByClassName(document, 'ol', 'post-context')); + } + function toggle() { + for (var i = 0; i < arguments.length; i++) { + var e = document.getElementById(arguments[i]); + if (e) { + e.style.display = e.style.display == 'none' ? 'block' : 'none'; + } + } + return false; + } + function varToggle(link, id) { + toggle('v' + id); + var s = link.getElementsByTagName('span')[0]; + var uarr = String.fromCharCode(0x25b6); + var darr = String.fromCharCode(0x25bc); + s.innerHTML = s.innerHTML == uarr ? darr : uarr; + return false; + } + //--> + </script> +</head> +<body> + +<div id="summary"> + <h1><%=h exception.class %> at <%=h path %></h1> + <h2><%=h exception.message %></h2> + <table><tr> + <th>Ruby</th> + <td><code><%=h frames.first.filename %></code>: in <code><%=h frames.first.function %></code>, line <%=h frames.first.lineno %></td> + </tr><tr> + <th>Web</th> + <td><code><%=h req.request_method %> <%=h(req.host + path)%></code></td> + </tr></table> + + <h3>Jump to:</h3> + <ul id="quicklinks"> + <li><a href="#get-info">GET</a></li> + <li><a href="#post-info">POST</a></li> + <li><a href="#cookie-info">Cookies</a></li> + <li><a href="#env-info">ENV</a></li> + </ul> +</div> + +<div id="traceback"> + <h2>Traceback <span>(innermost first)</span></h2> + <ul class="traceback"> +<% frames.each { |frame| %> + <li class="frame"> + <code><%=h frame.filename %></code>: in <code><%=h frame.function %></code> + + <% if frame.context_line %> + <div class="context" id="c<%=h frame.object_id %>"> + <% if frame.pre_context %> + <ol start="<%=h frame.pre_context_lineno+1 %>" class="pre-context" id="pre<%=h frame.object_id %>"> + <% frame.pre_context.each { |line| %> + <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line %></li> + <% } %> + </ol> + <% end %> + + <ol start="<%=h frame.lineno %>" class="context-line"> + <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h frame.context_line %><span>...</span></li></ol> + + <% if frame.post_context %> + <ol start='<%=h frame.lineno+1 %>' class="post-context" id="post<%=h frame.object_id %>"> + <% frame.post_context.each { |line| %> + <li onclick="toggle('pre<%=h frame.object_id %>', 'post<%=h frame.object_id %>')"><%=h line %></li> + <% } %> + </ol> + <% end %> + </div> + <% end %> + </li> +<% } %> + </ul> +</div> + +<div id="requestinfo"> + <h2>Request information</h2> + + <h3 id="get-info">GET</h3> + <% unless req.GET.empty? %> + <table class="req"> + <thead> + <tr> + <th>Variable</th> + <th>Value</th> + </tr> + </thead> + <tbody> + <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %> + <tr> + <td><%=h key %></td> + <td class="code"><div><%=h val.inspect %></div></td> + </tr> + <% } %> + </tbody> + </table> + <% else %> + <p>No GET data.</p> + <% end %> + + <h3 id="post-info">POST</h3> + <% unless req.POST.empty? %> + <table class="req"> + <thead> + <tr> + <th>Variable</th> + <th>Value</th> + </tr> + </thead> + <tbody> + <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %> + <tr> + <td><%=h key %></td> + <td class="code"><div><%=h val.inspect %></div></td> + </tr> + <% } %> + </tbody> + </table> + <% else %> + <p>No POST data.</p> + <% end %> + + + <h3 id="cookie-info">COOKIES</h3> + <% unless req.cookies.empty? %> + <table class="req"> + <thead> + <tr> + <th>Variable</th> + <th>Value</th> + </tr> + </thead> + <tbody> + <% req.cookies.each { |key, val| %> + <tr> + <td><%=h key %></td> + <td class="code"><div><%=h val.inspect %></div></td> + </tr> + <% } %> + </tbody> + </table> + <% else %> + <p>No cookie data.</p> + <% end %> + + <h3 id="env-info">Rack ENV</h3> + <table class="req"> + <thead> + <tr> + <th>Variable</th> + <th>Value</th> + </tr> + </thead> + <tbody> + <% env.sort_by { |k, v| k.to_s }.each { |key, val| %> + <tr> + <td><%=h key %></td> + <td class="code"><div><%=h val %></div></td> + </tr> + <% } %> + </tbody> + </table> + +</div> + +<div id="explanation"> + <p> + You're seeing this error because you use <code>Rack::ShowExceptions</code>. + </p> +</div> + +</body> +</html> +HTML + + # :startdoc: + end +end |