    """HTTPExceptions

    HTTPExceptions are for situations that are predicted by the
    HTTP spec. Where the ``200 OK`` response is typical, a
    ``404 Not Found`` or ``301 Moved Temporarily`` response is not
    entirely unexpected.

    `Application` catches all `HTTPException` exceptions (and subclasses
    of HTTPException), and instead of being errors these are translated
    into responses. In various places these can also be caught and
    changed, for instance an `HTTPAuthenticationRequired` could be
    turned into a normal login page.
    """

    from types import *
    from WebUtils.Funcs import htmlEncode

    try: # backward compatibility for Python < 2.3
        True, False
    except NameError:
        True, False = 1, 0

    class HTTPException(Exception):
        """HTTPException template class.

        Subclasses must define these variables (usually as class variables):

        `_code`:
            a tuple of the integer error code, and the short
            description that goes with it (like ``(200, "OK")``)
        `_description`:
            the long-winded description, to be presented
            in the response page. Or you can override description()
            if you want something more context-sensitive.

        """

        ## Error codes ##

        _description = 'An error occurred'

        def code(self):
            """The integer code."""
            return self._code[0]

        def codeMessage(self):
            """The message (like ``Not Found``) that goes with the code."""
            return self._code[1]

        ## HTML Description ##

        def html(self):
            """The error page.

            The HTML page that should be sent with the error,
            usually a description of the problem.

            """
            return '''
    <html><head><title>%(code)s %(title)s</title></head>
    <body>
    <h1>%(htTitle)s</h1>
    %(body)s
    </body></html>''' % {
                "htTitle": self.htTitle(),
                "title": self.title(),
                "body": self.htBody(),
                "code": self.code()
                }

        def title(self):
            """The title used in the HTML page."""
            return self.codeMessage()

        def htTitle(self):
            """The title, but it may include HTML markup (like italics)."""
            return self.title()

        def htBody(self):
            """The HTML body of the page."""
            body = self.htDescription()
            if self.args:
                body += ''.join(['<p>%s</p>\n' % str(l) for l in self.args])
            return body

        def description(self):
            """Error description.

            Possibly a plain text version of the error description,
            though usually just identical to `htDescription`.

            """
            return self._description

        def htDescription(self):
            """HTML error description.

            The HTML description of the error, for presentation
            to the browser user.

            """
            return self.description()

        ## Misc ##

        def headers(self):
            """Get headers.

            Additional headers that should be sent with the
            response, not including the Status header. For instance,
            the redirect exception adds a Location header.

            """
            return {}

        def setTransaction(self, trans):
            """Set transaction.

            When the exception is caught by `Application`, it tells
            the exception what the transaction is. This way you
            can resolve relative paths, or otherwise act in a manner
            sensitive of the context of the error.

            """
            self._transaction = trans

    class HTTPNotImplemented(HTTPException):
        """HTTPExcecption "not implemented" subclass.

        When methods (like GET, POST, PUT, PROPFIND, etc) are not
        implemented for this resource.

        """
        _code = 501, "Not Implemented"
        _description = "The method given is not yet implemented by this application"

    class HTTPForbidden(HTTPException):
        """HTTPExcecption "forbidden" subclass.

        When access is not allowed to this resource. If the user is anonymous,
        and must be authenticated, then HTTPAuthenticationRequired is a preferable
        exception. If the user should not be able to get to this resource (at
        least through the path they did), or is authenticated and still doesn't
        have access, or no one is allowed to view this, then HTTPForbidden would
        be the proper response.

        """
        _code = 403, 'Forbidden'
        _description = "You are not authorized to access this resource"

    class HTTPAuthenticationRequired(HTTPException):
        """HTTPExcecption "authentication required" subclass.

        HTTPAuthenticationRequired will usually cause the browser to open up an
        HTTP login box, and after getting login information from the user, the
        browser will resubmit the request. However, this should also trigger
        login pages in properly set up environments (though much code will not
        work this way).

        Browsers will usually not send authentication information unless they
        receive this response, even when other pages on the site have given 401
        responses before. So when using this authentication every request will
        usually be doubled, once without authentication, once with.

        """
        _code = 401, 'Authentication Required'
        _description = "You must log in to access this resource"
        def __init__(self, realm=None, *args):
            if not realm:
                realm = 'Password required'
            assert realm.find('"') == -1, 'Realm must not contain "'
            self._realm = realm
            HTTPException.__init__(self, *args)

        def headers(self):
            return {'WWW-Authenticate': 'Basic realm="%s"' % self._realm}

    # This is for wording mistakes. I'm unsure about their benefit.
    HTTPAuthorizationRequired = HTTPAuthenticationRequired
    """
    There is also an alias `HTTPAuthorizationRequired`, as it is hard
    to distinguish between these two names.
    """

    class HTTPMethodNotAllowed(HTTPException):
        """HTTPExcecption "method not allowed" subclass.

        When a method (like GET, PROPFIND, POST, etc) is not allowed
        on this resource (usually because it does not make sense, not
        because it is not permitted). Mostly for WebDAV.

        """
        _code = 405, 'Method Not Allowed'
        _description = 'The method is not supported on this resource'

    class HTTPConflict(HTTPException):
        """HTTPExcecption "conflict" subclass.

        When there's a locking conflict on this resource (in response to something
        like a PUT, not for most other conflicts). Mostly for WebDAV.

        """
        _code = 409, 'Conflict'

    class HTTPUnsupportedMediaType(HTTPException):
        """HTTPExcecption "unsupported media type" subclass."""
        _code = 415, 'Unsupported Media Type'

    class HTTPInsufficientStorage(HTTPException):
        """HTTPExcecption "insufficient storage" subclass.

        When there is not sufficient storage, usually in response to a PUT when
        there isn't enough disk space. Mostly for WebDAV.

        """
        _code = 507, 'Insufficient Storage'
        _description = 'There was not enough storage space on the server to complete your request'

    class HTTPPreconditionFailed(HTTPException):
        """HTTPExcecption "Precondition Failed" subclass.

        During compound, atomic operations, when a precondition for an early
        operation fail, then later operations in will fail with this code.
        Mostly for WebDAV.

        """
        _code = 412, 'Precondition Failed'

    class HTTPMovedPermanently(HTTPException):
        """HTTPExcecption "moved permanently" subclass.

        When a resource is permanently moved. The browser may remember this
        relocation, and later requests may skip requesting the original
        resource altogether.

        """
        _code = 301, 'Moved Permanently'

        def __init__(self, location=None, webkitLocation=None, *args):
            """Set destination.

            HTTPMovedPermanently needs a destination that you it should be
            directed to -- you can pass `location` *or* `webkitLocation` --
            if you pass `webkitLocation` it will be relative to the WebKit base
            (the portion through the adapter).
            """
            self._location = location
            self._webkitLocation = webkitLocation
            HTTPException.__init__(self, 301, 'Moved Permanently', *args)

        def location(self):
            """The location that we will be redirecting to."""
            if self._webkitLocation:
                environ = self._transaction.request().environ()
                if not self._webkitLocation.startswith('/'):
                    self._webkitLocation = '/' + self._webkitLocation
                location = 'http://%s%s%s' % (environ.get('HTTP_HOST',
                        environ.get('SERVER_NAME', 'localhost')),
                    environ.get('SCRIPT_NAME', ''), self._webkitLocation)
            else:
                location = self._location
            return location

        def headers(self):
            """We include a Location header."""
            return {'Location': self.location()}

        def description(self):
            return 'The resource you are accessing has been moved to' \
                ' <a href="%s">%s</a>' % ((htmlEncode(self.location()),)*2)

    class HTTPTemporaryRedirect(HTTPMovedPermanently):
        """HTTPExcecption "temporary tedirect" subclass.

        Like HTTPMovedPermanently, except the redirect is only valid for this
        request. Internally identical to HTTPMovedPermanently, except with a
        different response code. Browsers will check the server for each request
        to see where it's redirected to.

        """
        _code = 307, 'Temporary Redirect'

    # This is what people mean most often:
    HTTPRedirect = HTTPTemporaryRedirect

    class HTTPBadRequest(HTTPException):
        """HTTPExcecption "bad request" subclass.

        When the browser sends an invalid request.

        """
        _code = 400, 'Bad Request'

    class HTTPNotFound(HTTPException):
        """HTTPExcecption "not found" subclass.

        When the requested resource does not exist. To be more secretive,
        it is okay to return a 404 if access to the resource is not permitted
        (you are not required to use HTTPForbidden, though it makes it more
        clear why access was disallowed).

        """
        _code = 404, 'Not Found'
        _description = 'The resource you were trying to access was not found'

        def html(self):
            trans = self._transaction
            page = trans.application()._404Page
            if page:
                req = trans.request()
                url = req.adapterName() + req.urlPath()
                return page % url
            else:
                return HTTPException.html(self)