0001import cgi
0002import urllib
0003import warnings
0004import inspect
0005import Cookie as CookieEngine
0006
0007__all__ = ['NoDefault', 'htmlEncode', 'htmlDecode',
0008           'urlEncode', 'urlDecode',
0009           ]
0010
0011try:
0012    from MiscUtils import NoDefault
0013except ImportError:
0014    class NoDefault:
0015        pass
0016
0017def htmlEncode(s):
0018    return cgi.escape(s, 1)
0019
0020def htmlDecode(s):
0021    for char, code in [('&', '&'),
0022                       ('<', '&lt;'),
0023                       ('>', '&gt;'),
0024                       ('"', '&quot;')]:
0025        s = s.replace(code, char)
0026    return s
0027
0028urlDecode = urllib.unquote
0029urlEncode = urllib.quote
0030
0031def requestURI(dict):
0032    """
0033    Returns the request URI for a given CGI-style dictionary. Uses
0034    REQUEST_URI if available, otherwise constructs and returns it from
0035    SCRIPT_NAME, PATH_INFO and QUERY_STRING.
0036    """
0037    uri = dict.get('REQUEST_URI', None)
0038    if uri is None:
0039        uri = dict.get('SCRIPT_NAME', '') + dict.get('PATH_INFO', '')
0040        query = dict.get('QUERY_STRING', '')
0041        if query:
0042            uri = uri + '?' + query
0043    return uri
0044
0045def deprecated(msg=None):
0046    # @@: Right now this takes up a surprising amount of CPU time
0047    # (blech!  inspect is slow)
0048    return
0049    if not msg:
0050        frame = inspect.stack()[1]
0051        methodName = frame[3]
0052        msg = 'The use of %s is deprecated' % methodName
0053    warnings.warn(msg, DeprecationWarning, stacklevel=3)
0054
0055
0056
0057class Cookie:
0058    """
0059    Cookie is used to create cookies that have additional
0060    attributes beyond their value.
0061
0062    Note that web browsers don't typically send any information
0063    with the cookie other than it's value. Therefore
0064    `HTTPRequest.cookie` simply returns a value such as an
0065    integer or a string.
0066
0067    When the server sends cookies back to the browser, it can send
0068    a cookie that simply has a value, or the cookie can be
0069    accompanied by various attributes (domain, path, max-age, ...)
0070    as described in `RFC 2109`_. Therefore, in HTTPResponse,
0071    `setCookie` can take either an instance of the Cookie class,
0072    as defined in this module, or a value.
0073
0074    Note that Cookies values get pickled (see the `pickle` module),
0075    so you can set and get cookies that are integers, lists,
0076    dictionaries, etc.
0077
0078    .. _`RFC 2109`: ftp://ftp.isi.edu/in-notes/rfc2109.txt
0079    """
0080
0081    ## Future
0082    ##
0083    ##    * This class should provide error checking in the setFoo()
0084    ##      methods. Or maybe our internal Cookie implementation
0085    ##      already does that?
0086    ##    * This implementation is probably not as efficient as it
0087    ##      should be, [a] it works and [b] the interface is stable.
0088    ##      We can optimize later.
0089
0090    def __init__(self, name, value):
0091        """
0092        Create a cookie -- properties other than `name` and
0093        `value` are set with methods.
0094        """
0095
0096        self._cookies = CookieEngine.SimpleCookie()
0097        self._name = name
0098        self._value = value
0099        self._cookies[name] = value
0100        self._cookie = self._cookies[name]
0101
0102    """
0103    **Accessors**
0104    """
0105
0106    def comment(self):
0107        return self._cookie['comment']
0108
0109    def domain(self):
0110        return self._cookie['domain']
0111
0112    def maxAge(self):
0113        return self._cookie['max-age']
0114
0115    def expires(self):
0116        return self._cookie['expires']
0117
0118    def name(self):
0119        return self._name
0120
0121    def path(self):
0122        return self._cookie['path']
0123
0124    def isSecure(self):
0125        return self._cookie['secure']
0126
0127    def value(self):
0128        return self._value
0129
0130    def version(self):
0131        return self._cookie['version']
0132
0133
0134    """
0135    **Setters**
0136    """
0137
0138    def setComment(self, comment):
0139        self._cookie['comment'] = comment
0140
0141    def setDomain(self, domain):
0142        self._cookie['domain'] = domain
0143
0144    def setExpires(self, expires):
0145        self._cookie['expires'] = expires
0146
0147    def setMaxAge(self, maxAge):
0148        self._cookie['max-age'] = maxAge
0149
0150    def setPath(self, path):
0151        self._cookie['path'] = path
0152
0153    def setSecure(self, bool):
0154        self._cookie['secure'] = bool
0155
0156    def setValue(self, value):
0157        self._value = value
0158        self._cookies[self._name] = value
0159
0160    def setVersion(self, version):
0161        self._cookie['version'] = version
0162
0163
0164    """
0165    **Misc**
0166    """
0167
0168    def delete(self):
0169        """
0170        When sent, this should delete the cookie from the user's
0171        browser, by making it empty, expiring it in the past,
0172        and setting its max-age to 0.  One of these will delete
0173        the cookie for any browser (which one actually works
0174        depends on the browser).
0175        """
0176
0177        self._value = ''
0178        self._cookie['expires'] = "Mon, 01-Jan-1900 00:00:00 GMT"
0179        self._cookie['max-age'] = 0
0180        self._cookie['path'] = '/'
0181
0182
0183    def headerValue(self):
0184        """
0185        Returns a string with the value that should be
0186        used in the HTTP headers. """
0187
0188        items = self._cookies.items()
0189        assert(len(items)==1)
0190        return items[0][1].OutputString()