231 lines
7.1 KiB
Python
231 lines
7.1 KiB
Python
# portions adapted from Django <djangoproject.com> and web.py <webpy.org>
|
|
# Copyright (c) 2005, the Lawrence Journal-World
|
|
# Used under the modified BSD license:
|
|
# http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
|
|
|
|
from tornado import escape
|
|
import sys, urlparse, pprint, traceback
|
|
import os, os.path, base64
|
|
|
|
try:
|
|
from cStringIO import StringIO
|
|
except:
|
|
from StringIO import StringIO
|
|
|
|
whereami = os.path.join(os.getcwd(), __file__)
|
|
whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1])
|
|
|
|
class BaseObject(object): pass
|
|
class DebugBreakException(Exception): pass
|
|
|
|
def _dict_to_list(d):
|
|
items = d and d.items() or []
|
|
items.sort()
|
|
return items
|
|
|
|
def dicttable(d, kls='req', id=None):
|
|
return dicttable_items(_dict_to_list(d), kls, id)
|
|
|
|
def dicttable_items(items, kls='req', id=None):
|
|
output = ''
|
|
|
|
if items:
|
|
output += '<table class="%s"' % kls
|
|
if id: output += 'id="%s"' % id
|
|
output += '><thead><tr><th>Variable</th><th>Value</th></tr></thead><tbody>'
|
|
|
|
for k, v in items:
|
|
try:
|
|
output += '<tr><td>%s</td><td class="code"><div>%s</div></td></tr>' \
|
|
% (k, prettify(v))
|
|
except UnicodeDecodeError, e:
|
|
output += '<tr><td>%s (in base 64)</td><td class="code"><div>%s</div></td></tr>' \
|
|
% (k, base64.b64encode(v))
|
|
|
|
output += '</tbody></table>'
|
|
else:
|
|
output += '<p>No data.</p>'
|
|
|
|
return output
|
|
|
|
def dicttable_txt(d, tabbing):
|
|
return dicttable_items_txt(_dict_to_list(d), tabbing)
|
|
|
|
def dicttable_items_txt(items, tabbing):
|
|
if len(items) == 0: return ''
|
|
|
|
formatted_items = []
|
|
max_key_length = 0
|
|
|
|
for i in range(0, len(items)):
|
|
k = items[i][0]
|
|
v = items[i][1]
|
|
|
|
try:
|
|
formatted_items.append([k, unicode(v)])
|
|
except UnicodeDecodeError:
|
|
k += ' (in base 64)'
|
|
formatted_items.append([k, base64.b32encode(v)])
|
|
|
|
if len(k) > max_key_length: max_key_length = len(k)
|
|
|
|
tabbing = ' ' * tabbing
|
|
output = ''
|
|
|
|
for k, v in formatted_items:
|
|
spaces = ' ' * (max_key_length - len(k))
|
|
output += '%s%s%s = %s\n' % (tabbing, k, spaces, v)
|
|
|
|
return output
|
|
|
|
def prettify(x):
|
|
try:
|
|
out = pprint.pformat(unicode(x))
|
|
except UnicodeDecodeError, e:
|
|
raise e
|
|
except Exception, e:
|
|
out = '[could not display: <' + e.__class__.__name__ + \
|
|
': '+str(e)+'>]'
|
|
return out
|
|
|
|
def _get_lines_from_file(filename, lineno, context_lines):
|
|
"""
|
|
Returns context_lines before and after lineno from file.
|
|
Returns (pre_context_lineno, pre_context, context_line, post_context).
|
|
"""
|
|
|
|
try:
|
|
source = open(filename).readlines()
|
|
lower_bound = max(0, lineno - context_lines)
|
|
upper_bound = lineno + context_lines
|
|
|
|
pre_context = \
|
|
[line.strip('\n') for line in source[lower_bound:lineno]]
|
|
context_line = source[lineno].strip('\n')
|
|
post_context = \
|
|
[line.strip('\n') for line in source[lineno + 1:upper_bound]]
|
|
|
|
return lower_bound, pre_context, context_line, post_context
|
|
except (OSError, IOError):
|
|
return None, [], None, []
|
|
|
|
def _get_frames(tback, is_debug):
|
|
frames = []
|
|
|
|
while tback is not None:
|
|
if tback.tb_next == None and is_debug: break
|
|
|
|
filename = tback.tb_frame.f_code.co_filename
|
|
function = tback.tb_frame.f_code.co_name
|
|
lineno = tback.tb_lineno - 1
|
|
pre_context_lineno, pre_context, context_line, post_context = \
|
|
_get_lines_from_file(filename, lineno, 7)
|
|
|
|
frame = BaseObject()
|
|
frame.tback = tback
|
|
frame.filename = filename
|
|
frame.function = function
|
|
frame.lineno = lineno
|
|
frame.vars = tback.tb_frame.f_locals
|
|
frame.id = id(tback)
|
|
frame.pre_context = pre_context
|
|
frame.context_line = context_line
|
|
frame.post_context = post_context
|
|
frame.pre_context_lineno = pre_context_lineno
|
|
frames.append(frame)
|
|
|
|
tback = tback.tb_next
|
|
|
|
return frames
|
|
|
|
def _get_response_output(handler):
|
|
if handler._write_buffer:
|
|
response_output = "".join(handler._write_buffer)
|
|
|
|
if response_output:
|
|
# Don't write out empty chunks because that means
|
|
# END-OF-STREAM with chunked encoding
|
|
for transform in handler._transforms:
|
|
response_output = transform.transform_chunk(response_output)
|
|
else:
|
|
response_output = ''
|
|
|
|
return response_output
|
|
|
|
def _get_response_headers(handler):
|
|
return [(k, v) for (k, v) in handler._headers.iteritems()]
|
|
|
|
def render_html(handler):
|
|
exception_type, exception_value, tback = sys.exc_info()
|
|
is_debug = isinstance(exception_value, DebugBreakException)
|
|
|
|
frames = _get_frames(tback, is_debug)
|
|
frames.reverse()
|
|
|
|
if is_debug:
|
|
exception_type = 'Debug breakpoint'
|
|
exception_value = ''
|
|
|
|
urljoin = urlparse.urljoin
|
|
|
|
params = {
|
|
'exception_type': exception_type,
|
|
'exception_value': exception_value,
|
|
'frames': frames,
|
|
|
|
'request_input': handler.request.body,
|
|
'request_cookies': handler.cookies,
|
|
'request_headers': handler.request.headers,
|
|
|
|
'request_path': handler.request.uri,
|
|
'request_method': handler.request.method,
|
|
'response_output': _get_response_output(handler),
|
|
'response_headers': _get_response_headers(handler),
|
|
|
|
'dict': dict,
|
|
'str': str,
|
|
'prettify': prettify,
|
|
'dicttable': dicttable,
|
|
'dicttable_items': dicttable_items
|
|
}
|
|
|
|
return handler.render_string('error_template.html', **params)
|
|
|
|
def render_txt(handler):
|
|
return traceback.format_exc()
|
|
|
|
def _writeln(handler, text):
|
|
handler.write(text)
|
|
handler.write('\n')
|
|
|
|
def render_verbose_txt(handler):
|
|
exception_type, exception_value, tback = sys.exc_info()
|
|
is_debug = isinstance(exception_value, DebugBreakException)
|
|
frames = _get_frames(tback, is_debug)
|
|
|
|
buffer = StringIO()
|
|
|
|
_writeln(buffer, 'Error: ' + str(exception_type))
|
|
_writeln(buffer, 'Desc: ' + str(exception_value))
|
|
_writeln(buffer, '*' * 80)
|
|
|
|
_writeln(buffer, 'Traceback (most recent call last):')
|
|
for frame in frames:
|
|
_writeln(buffer, ' File "%s", line %s, in %s' % (frame.filename, frame.lineno, frame.function))
|
|
if frame.context_line: _writeln(buffer, ' ' + frame.context_line.strip())
|
|
if frame.vars: _writeln(buffer, dicttable_txt(frame.vars, 6))
|
|
|
|
_writeln(buffer, 'Response headers:')
|
|
_writeln(buffer, dicttable_items_txt(_get_response_headers(handler), 0))
|
|
|
|
_writeln(buffer, '\nResponse body:')
|
|
_writeln(buffer, _get_response_output(handler))
|
|
|
|
_writeln(buffer, '*' * 80)
|
|
_writeln(buffer, '\nRequest input:')
|
|
_writeln(buffer, handler.request.body)
|
|
|
|
_writeln(buffer, '\nRequest cookies:')
|
|
_writeln(buffer, dicttable_txt(handler.cookies, 0))
|
|
|
|
return buffer.getvalue() |