[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