1
"""Pylons' WSGI middlewares"""
5
from paste.deploy.converters import asbool
6
from paste.urlparser import StaticURLParser
7
from weberror.evalexception import EvalException
8
from weberror.errormiddleware import ErrorMiddleware
9
from webob import Request, Response
10
from webhelpers.html import literal
13
from pylons.error import template_error_formatters
14
from pylons.util import call_wsgi_application
16
__all__ = ['ErrorHandler', 'StaticJavascripts', 'error_document_template',
17
'footer_html', 'head_html', 'media_path']
19
log = logging.getLogger(__name__)
21
media_path = os.path.join(os.path.dirname(__file__), 'media')
24
<link rel="stylesheet" href="{{prefix}}/media/pylons/style/itraceback.css" \
25
type="text/css" media="screen" />"""
28
<script src="{{prefix}}/media/pylons/javascripts/traceback.js"></script>
33
traceback: "/tracebacks"
36
<div id="service_widget">
37
<h2 class="assistance">Online Assistance</h2>
40
<li class="nav active"><a class="overview" href="#">Overview</a></li>
41
<li class="nav"><a class="search" href="#">Search Mail Lists</a></li>
42
<li class="nav"><a class="posttraceback" href="#">Post Traceback</a></li>
45
<div class="clearfix"> </div>
46
<div class="overviewtab">
47
<b>Looking for help?</b>
49
<p>Here are a few tips for troubleshooting if the above traceback isn't
53
<li>Search the mail list</li>
54
<li>Post the traceback, and ask for help on IRC</li>
55
<li>Post a message to the mail list, referring to the posted traceback</li>
58
<div class="posttracebacktab">
59
<p><b>Note:</b> Clicking this button will post your traceback to the PylonsHQ website.
60
The traceback includes the module names, Python version, and lines of code that you
61
can see above. All tracebacks are posted anonymously unless you're logged into the
62
PylonsHQ website in this browser.</p>
63
<input type="button" href="#" class="submit_traceback" value="Send TraceBack to PylonsHQ" style="text-align: center;"/>
66
<div class="searchtab">
67
<p>The following mail lists will be searched:<br />
68
<input type="checkbox" name="lists" value="pylons" checked="checked" /> Pylons<br />
69
<input type="checkbox" name="lists" value="python" /> Python<br />
70
<input type="checkbox" name="lists" value="mako" /> Mako<br />
71
<input type="checkbox" name="lists" value="sqlalchemy" /> SQLAlchemy</p>
72
<p class="query">for: <input type="text" name="query" class="query" /></p>
74
<p><input type="submit" value="Search" /></p>
75
<div class="searchresults">
81
<div id="pylons_logo">\
82
<img src="{{prefix}}/media/pylons/img/pylons-powered-02.png" /></div>
83
<div class="credits">Pylons version %s</div>"""
85
report_libs = ['pylons', 'genshi', 'sqlalchemy']
87
def ErrorHandler(app, global_conf, **errorware):
88
"""ErrorHandler Toggle
90
If debug is enabled, this function will return the app wrapped in
91
the WebError ``EvalException`` middleware which displays
92
interactive debugging sessions when a traceback occurs.
94
Otherwise, the app will be wrapped in the WebError
95
``ErrorMiddleware``, and the ``errorware`` dict will be passed into
96
it. The ``ErrorMiddleware`` handles sending an email to the address
97
listed in the .ini file, under ``email_to``.
100
if asbool(global_conf.get('debug')):
101
footer = footer_html % (pylons.config.get('traceback_host',
104
py_media = dict(pylons=media_path)
105
app = EvalException(app, global_conf,
106
templating_formatters=template_error_formatters,
107
media_paths=py_media, head_html=head_html,
109
libraries=report_libs)
111
app = ErrorMiddleware(app, global_conf, **errorware)
115
class StatusCodeRedirect(object):
116
"""Internally redirects a request based on status code
118
StatusCodeRedirect watches the response of the app it wraps. If the
119
response is an error code in the errors sequence passed the request
120
will be re-run with the path URL set to the path passed in.
122
This operation is non-recursive and the output of the second
123
request will be used no matter what it is.
125
Should an application wish to bypass the error response (ie, to
126
purposely return a 401), set
127
``environ['pylons.status_code_redirect'] = True`` in the application.
130
def __init__(self, app, errors=(400, 401, 403, 404),
131
path='/error/document'):
132
"""Initialize the ErrorRedirect
135
A sequence (list, tuple) of error code integers that should
138
The path to set for the next request down to the
143
self.error_path = path
145
# Transform errors to str for comparison
146
self.errors = tuple([str(x) for x in errors])
148
def __call__(self, environ, start_response):
149
status, headers, app_iter, exc_info = call_wsgi_application(
150
self.app, environ, catch_exc_info=True)
151
if status[:3] in self.errors and \
152
'pylons.status_code_redirect' not in environ and self.error_path:
153
# Create a response object
154
environ['pylons.original_response'] = Response(
155
status=status, headerlist=headers, app_iter=app_iter)
156
environ['pylons.original_request'] = Request(environ)
158
# Create a new environ to avoid touching the original request data
159
new_environ = environ.copy()
160
new_environ['PATH_INFO'] = self.error_path
162
newstatus, headers, app_iter, exc_info = call_wsgi_application(
163
self.app, new_environ, catch_exc_info=True)
164
start_response(status, headers, exc_info)
168
error_document_template = literal("""\
169
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
170
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
172
<title>Server Error %(code)s</title>
174
<link rel="stylesheet" href="%(prefix)s/error/style/black.css" type="text/css" media="screen" />
176
<!-- Favorite Icons -->
177
<link rel="icon" href="%(prefix)s/error/img/favicon.ico" type="image/png" />
179
<style type="text/css">