[CalendarServer-changes] [8086] CalendarServer/branches/users/glyph/other-html/twext/web2/error.py
source_changes at macosforge.org
source_changes at macosforge.org
Tue Sep 13 12:11:40 PDT 2011
Revision: 8086
http://trac.macosforge.org/projects/calendarserver/changeset/8086
Author: glyph at apple.com
Date: 2011-09-13 12:11:40 -0700 (Tue, 13 Sep 2011)
Log Message:
-----------
Replace error handler with templated version. A bit more verbose this way, but oh well.
Modified Paths:
--------------
CalendarServer/branches/users/glyph/other-html/twext/web2/error.py
Modified: CalendarServer/branches/users/glyph/other-html/twext/web2/error.py
===================================================================
--- CalendarServer/branches/users/glyph/other-html/twext/web2/error.py 2011-09-13 19:11:33 UTC (rev 8085)
+++ CalendarServer/branches/users/glyph/other-html/twext/web2/error.py 2011-09-13 19:11:40 UTC (rev 8086)
@@ -1,3 +1,4 @@
+# -*- test-case-name: twext.web2.test.test_log -*-
##
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
# Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
@@ -27,8 +28,20 @@
"""
from twext.web2 import stream, http_headers
-from twext.web2.responsecode import *
+from twext.web2.responsecode import (
+ MOVED_PERMANENTLY, FOUND, SEE_OTHER, USE_PROXY, TEMPORARY_REDIRECT,
+ BAD_REQUEST, UNAUTHORIZED, PAYMENT_REQUIRED, FORBIDDEN, NOT_FOUND,
+ NOT_ALLOWED, NOT_ACCEPTABLE, PROXY_AUTH_REQUIRED, REQUEST_TIMEOUT, CONFLICT,
+ GONE, LENGTH_REQUIRED, PRECONDITION_FAILED, REQUEST_ENTITY_TOO_LARGE,
+ REQUEST_URI_TOO_LONG, UNSUPPORTED_MEDIA_TYPE,
+ REQUESTED_RANGE_NOT_SATISFIABLE, EXPECTATION_FAILED, INTERNAL_SERVER_ERROR,
+ NOT_IMPLEMENTED, BAD_GATEWAY, SERVICE_UNAVAILABLE, GATEWAY_TIMEOUT,
+ HTTP_VERSION_NOT_SUPPORTED, INSUFFICIENT_STORAGE_SPACE, NOT_EXTENDED,
+ RESPONSES,
+)
+from twisted.web.template import Element, flattenString, XMLString, renderer
+
# 300 - Should include entity with choices
# 301 -
# 304 - Must include Date, ETag, Content-Location, Expires, Cache-Control, Vary.
@@ -40,55 +53,101 @@
# 413 - May include Retry-After
# 416 - Should include Content-Range
# 503 - Should include Retry-After
-
ERROR_MESSAGES = {
# 300
# no MULTIPLE_CHOICES
- MOVED_PERMANENTLY: 'The document has permanently moved <a href="%(location)s">here</a>.',
- FOUND: 'The document has temporarily moved <a href="%(location)s">here</a>.',
- SEE_OTHER: 'The results are available <a href="%(location)s">here</a>.',
+ MOVED_PERMANENTLY: 'The document has permanently moved <a>here<t:attr name="href"><t:slot name="location"></t:slot></t:attr></a>.',
+ FOUND: 'The document has temporarily moved <a>here<t:attr name="href"><t:slot name="location"></t:slot></t:attr></a>.',
+ SEE_OTHER: 'The results are available <a>here<t:attr name="href"><t:slot name="location"></t:slot></t:attr></a>.',
# no NOT_MODIFIED
- USE_PROXY: "Access to this resource must be through the proxy %(location)s.",
+ USE_PROXY: 'Access to this resource must be through the proxy <t:slot name="location"></t:slot>.',
# 306 unused
- TEMPORARY_REDIRECT: 'The document has temporarily moved <a href="%(location)s">here</a>.',
+ TEMPORARY_REDIRECT: 'The document has temporarily moved <a>here<t:attr name="href"><t:slot name="location"></t:slot></t:attr></a>.',
# 400
- BAD_REQUEST: "Your browser sent an invalid request.",
- UNAUTHORIZED: "You are not authorized to view the resource at %(uri)s. Perhaps you entered a wrong password, or perhaps your browser doesn't support authentication.",
- PAYMENT_REQUIRED: "Payment Required (useful result code, this...).",
- FORBIDDEN: "You don't have permission to access %(uri)s.",
- NOT_FOUND: "The resource %(uri)s cannot be found.",
- NOT_ALLOWED: "The requested method %(method)s is not supported by %(uri)s.",
- NOT_ACCEPTABLE: "No representation of %(uri)s that is acceptable to your client could be found.",
- PROXY_AUTH_REQUIRED: "You are not authorized to view the resource at %(uri)s. Perhaps you entered a wrong password, or perhaps your browser doesn't support authentication.",
- REQUEST_TIMEOUT: "Server timed out waiting for your client to finish sending the HTTP request.",
- CONFLICT: "Conflict (?)",
- GONE: "The resource %(uri)s has been permanently removed.",
- LENGTH_REQUIRED: "The resource %(uri)s requires a Content-Length header.",
- PRECONDITION_FAILED: "A precondition evaluated to false.",
- REQUEST_ENTITY_TOO_LARGE: "The provided request entity data is too longer than the maximum for the method %(method)s at %(uri)s.",
- REQUEST_URI_TOO_LONG: "The request URL is longer than the maximum on this server.",
- UNSUPPORTED_MEDIA_TYPE: "The provided request data has a format not understood by the resource at %(uri)s.",
- REQUESTED_RANGE_NOT_SATISFIABLE: "None of the ranges given in the Range request header are satisfiable by the resource %(uri)s.",
- EXPECTATION_FAILED: "The server does support one of the expectations given in the Expect header.",
+ BAD_REQUEST: 'Your browser sent an invalid request.',
+ UNAUTHORIZED: 'You are not authorized to view the resource at <t:slot name="uri"></t:slot>. Perhaps you entered a wrong password, or perhaps your browser doesn\'t support authentication.',
+ PAYMENT_REQUIRED: 'Payment Required (useful result code, this...).',
+ FORBIDDEN: 'You don\'t have permission to access <t:slot name="uri"></t:slot>.',
+ NOT_FOUND: 'The resource <t:slot name="uri"></t:slot> cannot be found.',
+ NOT_ALLOWED: 'The requested method <t:slot name="method"></t:slot> is not supported by <t:slot name="uri"></t:slot>.',
+ NOT_ACCEPTABLE: 'No representation of <t:slot name="uri"></t:slot> that is acceptable to your client could be found.',
+ PROXY_AUTH_REQUIRED: 'You are not authorized to view the resource at <t:slot name="uri"></t:slot>. Perhaps you entered a wrong password, or perhaps your browser doesn\'t support authentication.',
+ REQUEST_TIMEOUT: 'Server timed out waiting for your client to finish sending the HTTP request.',
+ CONFLICT: 'Conflict (?)',
+ GONE: 'The resource <t:slot name="uri"></t:slot> has been permanently removed.',
+ LENGTH_REQUIRED: 'The resource <t:slot name="uri"></t:slot> requires a Content-Length header.',
+ PRECONDITION_FAILED: 'A precondition evaluated to false.',
+ REQUEST_ENTITY_TOO_LARGE: 'The provided request entity data is too longer than the maximum for the method <t:slot name="method"></t:slot> at <t:slot name="uri"></t:slot>.',
+ REQUEST_URI_TOO_LONG: 'The request URL is longer than the maximum on this server.',
+ UNSUPPORTED_MEDIA_TYPE: 'The provided request data has a format not understood by the resource at <t:slot name="uri"></t:slot>.',
+ REQUESTED_RANGE_NOT_SATISFIABLE: 'None of the ranges given in the Range request header are satisfiable by the resource <t:slot name="uri"></t:slot>.',
+ EXPECTATION_FAILED: 'The server does support one of the expectations given in the Expect header.',
# 500
- INTERNAL_SERVER_ERROR: "An internal error occurred trying to process your request. Sorry.",
- NOT_IMPLEMENTED: "Some functionality requested is not implemented on this server.",
- BAD_GATEWAY: "An upstream server returned an invalid response.",
- SERVICE_UNAVAILABLE: "This server cannot service your request becaues it is overloaded.",
- GATEWAY_TIMEOUT: "An upstream server is not responding.",
- HTTP_VERSION_NOT_SUPPORTED: "HTTP Version not supported.",
- INSUFFICIENT_STORAGE_SPACE: "There is insufficient storage space available to perform that request.",
- NOT_EXTENDED: "This server does not support the a mandatory extension requested."
+ INTERNAL_SERVER_ERROR: 'An internal error occurred trying to process your request. Sorry.',
+ NOT_IMPLEMENTED: 'Some functionality requested is not implemented on this server.',
+ BAD_GATEWAY: 'An upstream server returned an invalid response.',
+ SERVICE_UNAVAILABLE: 'This server cannot service your request becaues it is overloaded.',
+ GATEWAY_TIMEOUT: 'An upstream server is not responding.',
+ HTTP_VERSION_NOT_SUPPORTED: 'HTTP Version not supported.',
+ INSUFFICIENT_STORAGE_SPACE: 'There is insufficient storage space available to perform that request.',
+ NOT_EXTENDED: 'This server does not support the a mandatory extension requested.'
}
-# Is there a good place to keep this function?
-def _escape(original):
- if original is None:
- return None
- return original.replace("&", "&").replace("<", "<").replace(">", ">").replace("\"", """)
+
+class DefaultErrorElement(Element):
+ """
+ An L{ErrorElement} is an L{Element} that renders some HTML for the default
+ rendering of an error page.
+ """
+
+ loader = XMLString("""
+ <html xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1"
+ t:render="error">
+ <head>
+ <title><t:slot name="code"/> <t:slot name="title"/></title>
+ </head>
+ <body>
+ <h1><t:slot name="title" /></h1>
+ <t:slot name="message" />
+ </body>
+ </html>
+ """)
+
+ def __init__(self, request, response):
+ super(DefaultErrorElement, self).__init__()
+ self.request = request
+ self.response = response
+
+
+ @renderer
+ def error(self, request, tag):
+ """
+ Top-level renderer for page.
+ """
+ return tag.fillSlots(
+ code=str(self.response.code),
+ title=RESPONSES.get(self.response.code),
+ message=self.loadMessage(self.response.code).fillSlots(
+ uri=self.request.uri,
+ location=self.response.headers.getHeader('location'),
+ method=self.request.method,
+ )
+ )
+
+
+ def loadMessage(self, code):
+ tag = XMLString(('<t:transparent xmlns:t="http://twistedmatrix.com/'
+ 'ns/twisted.web.template/0.1">') +
+ ERROR_MESSAGES.get(code, "") +
+ '</t:transparent>').load()[0]
+ return tag
+
+
+
+
def defaultErrorHandler(request, response):
if response.stream is not None:
# Already got an error message
@@ -96,28 +155,35 @@
if response.code < 300:
# We only do error messages
return response
-
+
message = ERROR_MESSAGES.get(response.code, None)
if message is None:
# No message specified for that code
return response
-
+
message = message % {
- 'uri':_escape(request.uri),
- 'location':_escape(response.headers.getHeader('location')),
- 'method':_escape(request.method)
- }
-
- title = RESPONSES.get(response.code, "")
- body = ("<html><head><title>%d %s</title></head>"
- "<body><h1>%s</h1>%s</body></html>") % (
- response.code, title, title, message)
-
- response.headers.setHeader("content-type", http_headers.MimeType('text', 'html', {'charset':'utf-8'}))
+ 'uri': request.uri,
+ 'location': response.headers.getHeader('location'),
+ 'method': request.method,
+ }
+ data = []
+ error = []
+ (flattenString(request, DefaultErrorElement(request, response))
+ .addCallbacks(data.append, error.append))
+ # No deferreds from our renderers above, so this has always already fired.
+ if data:
+ subtype = 'html'
+ body = data[0]
+ else:
+ subtype = 'error'
+ data = 'Error in default error handler:\n' + error[0].getTraceback()
+ ctype = http_headers.MimeType('text', subtype,
+ {'charset':'utf-8'})
+ response.headers.setHeader("content-type", ctype)
response.stream = stream.MemoryStream(body)
-
return response
defaultErrorHandler.handleErrors = True
__all__ = ['defaultErrorHandler',]
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20110913/c162db07/attachment-0001.html>
More information about the calendarserver-changes
mailing list