Latest Version: 0.9.6.2
/Users/bbangert/Programming/Python/pylons/pylons/controllers/util.py
0001"""Utility functions available for use by Controllers
0002
0003``etag_cache``, ``redirect_to``, and ``abort``.
0004"""
0005import logging
0006import warnings
0007
0008import paste.httpexceptions as httpexceptions
0009
0010from routes import url_for
0011
0012import pylons
0013import pylons.legacy
0014
0015__all__ = ['abort', 'etag_cache', 'redirect_to']
0016
0017log = logging.getLogger(__name__)
0018
0019def etag_cache(key=None):
0020    """Use the HTTP Entity Tag cache for Browser side caching
0021    
0022    If a "If-None-Match" header is found, and equivilant to ``key``, then
0023    a ``304`` HTTP message will be returned with the ETag to tell the browser
0024    that it should use its current cache of the page.
0025    
0026    Otherwise, the ETag header will be added to the response headers.
0027    
0028    Suggested use is within a Controller Action like so:
0029    
0030    .. code-block:: Python
0031    
0032        import pylons
0033        
0034        class YourController(BaseController):
0035            def index(self):
0036                etag_cache(key=1)
0037                return render('/splash.mako')
0038    
0039    .. Note:: 
0040        This works because etag_cache will raise an HTTPNotModified
0041        exception if the ETag recieved matches the key provided.
0042    """
0043    if_none_match = pylons.request.environ.get('HTTP_IF_NONE_MATCH', None)
0044    pylons.response.headers['ETag'] = key
0045    if str(key) == if_none_match:
0046        log.debug("ETag match, returning 304 HTTP Not Modified Response")
0047        raise httpexceptions.HTTPNotModified()
0048    else:
0049        log.debug("ETag didn't match, returning response object")
0050        return pylons.response
0051
0052
0053def abort(status_code=None, detail="", headers=None, comment=None):
0054    """Aborts the request immediately by returning an HTTP exception
0055    
0056    In the event that the status_code is a 300 series error, the detail 
0057    attribute will be used as the Location header should one not be specified
0058    in the headers attribute.
0059    """
0060    exc = httpexceptions.get_exception(status_code)(detail, headers, comment)
0061    log.debug("Aborting request, status: %s, detail: %r, headers: %r, "
0062              "comment: %r", status_code, detail, headers, comment)
0063    raise exc
0064
0065
0066def redirect_to(*args, **kargs):
0067    """Raises a redirect exception
0068    
0069    Optionally, a _code variable may be passed with the status code of the 
0070    redirect, ie:
0071
0072    .. code-block:: Python
0073
0074        redirect_to('home_page', _code=303)
0075    
0076    ``Deprecated``
0077    A Response object can be passed in as _response which will have the headers
0078    and cookies extracted from it and added into the redirect issued."""
0079    response = kargs.pop('_response', None)
0080    status_code = kargs.pop('_code', 302)
0081    exc = httpexceptions.get_exception(status_code)
0082    found = exc(url_for(*args, **kargs))
0083    log.debug("Generating %s redirect" % status_code)
0084    if response:
0085        warnings.warn(pylons.legacy.redirect_response_warning,
0086                      PendingDeprecationWarning, 2)
0087        log.debug("Merging provided Response object into redirect")
0088        if str(response.status_code).startswith('3'):
0089            found.code = response.status_code
0090        for c in response.cookies.values():
0091            found.headers.add('Set-Cookie', c.output(header=''))
0092    raise found

Top