[Web-SIG] wsgi.fatal_errors
tony at lownds.com
tony at lownds.com
Tue Aug 31 08:15:55 CEST 2004
> Here are some changes I've proposed in the last few days to resolve issues
> people brought up, but which I haven't gotten much feedback on:
>
> * 'wsgi.fatal_errors' key for exceptions that apps and middleware
> shouldn't
> trap
>
What about defining an exception class that applications can raise with an
HTML payload, which servers are supposed to send the to the client?
Middleware should be free to alter the payload as much as they like. The
server should not send the payload when content-type is not html.
By using exceptions as a backchannel, the application and middleware do
not have to keep track of the state to sanely handle an error.
With these examples, the FormatExceptions middleware really needs to be
the "innermost" middleware. I think exception-handling middleware
independent of how it is stacked is a non-goal.
For example,
def an_application(env, start_response):
try:
form = read_form(env)
html = do_work(form)
write = start_response('200 OK', [('Content-type', 'text/html')])
return [html]
except:
import cgitb
cgitb.html
raise env['wsgi.error_class'], cgitb.html(sys.exc_info())
...and middleware that formats the exception:
def FormatExceptions(app):
import sys, cgitb
def middleware(env, start_response):
try:
return app(env, start_response)
except:
raise env['wsgi.error_class'], cgitb.html(sys.exc_info())
return middleware
...and more complicated middleware that uses this concept:
class AddContent:
def __init__(self, app, header='', footer=''):
self.app = app
self.header = header
self.footer = footer
def __call__(self, env, start_response):
return AddContentHandler(env, start_response, self).run()
def add_length(self, length):
return length + len(self.header) + len(self.footer)
class AddContentHandler:
def __init__(self, add_content, env, start_response):
self.env = env
self.orig_start_response = start_response
self.add_content = add_content
self.written_header = False
self.publish_extension()
def publish_extension(self):
self.env['wsgi.extensions'].append('add_content')
self.env['add_content.instance'].append(add_content)
def start_response(self, status, headers):
self.set_headers(headers)
self.check_content_length()
self.orig_write = self.orig_start_response(status,
self.rebuild_headers())
return self.write
def write(self, data):
if not self.written_header:
self.orig_write(self.add_content.header)
self.written_header = True
return self.orig_write(data)
def run(self):
try:
result = self.add_content.app(self.env, self.start_response)
except self.env['wsgi.error_class'], e:
# wrap exception html -- try not to duplicate header
html = str(e)
if self.written_header:
self.written_header = True
html = self. add_content.header + html
html += self. add_content.footer
raise self.env['wsgi.error_class'], html
else:
self.result = iter(result)
return self
def __iter__(self):
if not self.written_header:
self.written_header = True
yield self.add_content.header
for i in self.result:
yield i
yield self.add_content.footer
-Tony
More information about the Web-SIG
mailing list