+++ /dev/null
-#!/usr/bin/env python\r
-#\r
-\r
-####\r
-# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>\r
-#\r
-# All Rights Reserved\r
-#\r
-# Permission to use, copy, modify, and distribute this software\r
-# and its documentation for any purpose and without fee is hereby\r
-# granted, provided that the above copyright notice appear in all\r
-# copies and that both that copyright notice and this permission\r
-# notice appear in supporting documentation, and that the name of\r
-# Timothy O'Malley not be used in advertising or publicity\r
-# pertaining to distribution of the software without specific, written\r
-# prior permission.\r
-#\r
-# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS\r
-# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r
-# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR\r
-# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,\r
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\r
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r
-# PERFORMANCE OF THIS SOFTWARE.\r
-#\r
-####\r
-#\r
-# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp\r
-# by Timothy O'Malley <timo@alum.mit.edu>\r
-#\r
-# Cookie.py is a Python module for the handling of HTTP\r
-# cookies as a Python dictionary. See RFC 2109 for more\r
-# information on cookies.\r
-#\r
-# The original idea to treat Cookies as a dictionary came from\r
-# Dave Mitchell (davem@magnet.com) in 1995, when he released the\r
-# first version of nscookie.py.\r
-#\r
-####\r
-\r
-r"""\r
-Here's a sample session to show how to use this module.\r
-At the moment, this is the only documentation.\r
-\r
-The Basics\r
-----------\r
-\r
-Importing is easy..\r
-\r
- >>> import Cookie\r
-\r
-Most of the time you start by creating a cookie. Cookies come in\r
-three flavors, each with slightly different encoding semantics, but\r
-more on that later.\r
-\r
- >>> C = Cookie.SimpleCookie()\r
- >>> C = Cookie.SerialCookie()\r
- >>> C = Cookie.SmartCookie()\r
-\r
-[Note: Long-time users of Cookie.py will remember using\r
-Cookie.Cookie() to create an Cookie object. Although deprecated, it\r
-is still supported by the code. See the Backward Compatibility notes\r
-for more information.]\r
-\r
-Once you've created your Cookie, you can add values just as if it were\r
-a dictionary.\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C["fig"] = "newton"\r
- >>> C["sugar"] = "wafer"\r
- >>> C.output()\r
- 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'\r
-\r
-Notice that the printable representation of a Cookie is the\r
-appropriate format for a Set-Cookie: header. This is the\r
-default behavior. You can change the header and printed\r
-attributes by using the .output() function\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C["rocky"] = "road"\r
- >>> C["rocky"]["path"] = "/cookie"\r
- >>> print C.output(header="Cookie:")\r
- Cookie: rocky=road; Path=/cookie\r
- >>> print C.output(attrs=[], header="Cookie:")\r
- Cookie: rocky=road\r
-\r
-The load() method of a Cookie extracts cookies from a string. In a\r
-CGI script, you would use this method to extract the cookies from the\r
-HTTP_COOKIE environment variable.\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C.load("chips=ahoy; vienna=finger")\r
- >>> C.output()\r
- 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'\r
-\r
-The load() method is darn-tootin smart about identifying cookies\r
-within a string. Escaped quotation marks, nested semicolons, and other\r
-such trickeries do not confuse it.\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')\r
- >>> print C\r
- Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"\r
-\r
-Each element of the Cookie also supports all of the RFC 2109\r
-Cookie attributes. Here's an example which sets the Path\r
-attribute.\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C["oreo"] = "doublestuff"\r
- >>> C["oreo"]["path"] = "/"\r
- >>> print C\r
- Set-Cookie: oreo=doublestuff; Path=/\r
-\r
-Each dictionary element has a 'value' attribute, which gives you\r
-back the value associated with the key.\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C["twix"] = "none for you"\r
- >>> C["twix"].value\r
- 'none for you'\r
-\r
-\r
-A Bit More Advanced\r
--------------------\r
-\r
-As mentioned before, there are three different flavors of Cookie\r
-objects, each with different encoding/decoding semantics. This\r
-section briefly discusses the differences.\r
-\r
-SimpleCookie\r
-\r
-The SimpleCookie expects that all values should be standard strings.\r
-Just to be sure, SimpleCookie invokes the str() builtin to convert\r
-the value to a string, when the values are set dictionary-style.\r
-\r
- >>> C = Cookie.SimpleCookie()\r
- >>> C["number"] = 7\r
- >>> C["string"] = "seven"\r
- >>> C["number"].value\r
- '7'\r
- >>> C["string"].value\r
- 'seven'\r
- >>> C.output()\r
- 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'\r
-\r
-\r
-SerialCookie\r
-\r
-The SerialCookie expects that all values should be serialized using\r
-cPickle (or pickle, if cPickle isn't available). As a result of\r
-serializing, SerialCookie can save almost any Python object to a\r
-value, and recover the exact same object when the cookie has been\r
-returned. (SerialCookie can yield some strange-looking cookie\r
-values, however.)\r
-\r
- >>> C = Cookie.SerialCookie()\r
- >>> C["number"] = 7\r
- >>> C["string"] = "seven"\r
- >>> C["number"].value\r
- 7\r
- >>> C["string"].value\r
- 'seven'\r
- >>> C.output()\r
- 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'\r
-\r
-Be warned, however, if SerialCookie cannot de-serialize a value (because\r
-it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.\r
-\r
-\r
-SmartCookie\r
-\r
-The SmartCookie combines aspects of each of the other two flavors.\r
-When setting a value in a dictionary-fashion, the SmartCookie will\r
-serialize (ala cPickle) the value *if and only if* it isn't a\r
-Python string. String objects are *not* serialized. Similarly,\r
-when the load() method parses out values, it attempts to de-serialize\r
-the value. If it fails, then it fallsback to treating the value\r
-as a string.\r
-\r
- >>> C = Cookie.SmartCookie()\r
- >>> C["number"] = 7\r
- >>> C["string"] = "seven"\r
- >>> C["number"].value\r
- 7\r
- >>> C["string"].value\r
- 'seven'\r
- >>> C.output()\r
- 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'\r
-\r
-\r
-Backwards Compatibility\r
------------------------\r
-\r
-In order to keep compatibilty with earlier versions of Cookie.py,\r
-it is still possible to use Cookie.Cookie() to create a Cookie. In\r
-fact, this simply returns a SmartCookie.\r
-\r
- >>> C = Cookie.Cookie()\r
- >>> print C.__class__.__name__\r
- SmartCookie\r
-\r
-\r
-Finis.\r
-""" #"\r
-# ^\r
-# |----helps out font-lock\r
-\r
-#\r
-# Import our required modules\r
-#\r
-import string\r
-\r
-try:\r
- from cPickle import dumps, loads\r
-except ImportError:\r
- from pickle import dumps, loads\r
-\r
-import re, warnings\r
-\r
-__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",\r
- "SmartCookie","Cookie"]\r
-\r
-_nulljoin = ''.join\r
-_semispacejoin = '; '.join\r
-_spacejoin = ' '.join\r
-\r
-#\r
-# Define an exception visible to External modules\r
-#\r
-class CookieError(Exception):\r
- pass\r
-\r
-\r
-# These quoting routines conform to the RFC2109 specification, which in\r
-# turn references the character definitions from RFC2068. They provide\r
-# a two-way quoting algorithm. Any non-text character is translated\r
-# into a 4 character sequence: a forward-slash followed by the\r
-# three-digit octal equivalent of the character. Any '\' or '"' is\r
-# quoted with a preceeding '\' slash.\r
-#\r
-# These are taken from RFC2068 and RFC2109.\r
-# _LegalChars is the list of chars which don't require "'s\r
-# _Translator hash-table for fast quoting\r
-#\r
-_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"\r
-_Translator = {\r
- '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',\r
- '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',\r
- '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',\r
- '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',\r
- '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',\r
- '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',\r
- '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',\r
- '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',\r
- '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',\r
- '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',\r
- '\036' : '\\036', '\037' : '\\037',\r
-\r
- # Because of the way browsers really handle cookies (as opposed\r
- # to what the RFC says) we also encode , and ;\r
-\r
- ',' : '\\054', ';' : '\\073',\r
-\r
- '"' : '\\"', '\\' : '\\\\',\r
-\r
- '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',\r
- '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',\r
- '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',\r
- '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',\r
- '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',\r
- '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',\r
- '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',\r
- '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',\r
- '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',\r
- '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',\r
- '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',\r
- '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',\r
- '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',\r
- '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',\r
- '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',\r
- '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',\r
- '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',\r
- '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',\r
- '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',\r
- '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',\r
- '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',\r
- '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',\r
- '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',\r
- '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',\r
- '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',\r
- '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',\r
- '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',\r
- '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',\r
- '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',\r
- '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',\r
- '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',\r
- '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',\r
- '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',\r
- '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',\r
- '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',\r
- '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',\r
- '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',\r
- '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',\r
- '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',\r
- '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',\r
- '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',\r
- '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',\r
- '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'\r
- }\r
-\r
-_idmap = ''.join(chr(x) for x in xrange(256))\r
-\r
-def _quote(str, LegalChars=_LegalChars,\r
- idmap=_idmap, translate=string.translate):\r
- #\r
- # If the string does not need to be double-quoted,\r
- # then just return the string. Otherwise, surround\r
- # the string in doublequotes and precede quote (with a \)\r
- # special characters.\r
- #\r
- if "" == translate(str, idmap, LegalChars):\r
- return str\r
- else:\r
- return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'\r
-# end _quote\r
-\r
-\r
-_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")\r
-_QuotePatt = re.compile(r"[\\].")\r
-\r
-def _unquote(str):\r
- # If there aren't any doublequotes,\r
- # then there can't be any special characters. See RFC 2109.\r
- if len(str) < 2:\r
- return str\r
- if str[0] != '"' or str[-1] != '"':\r
- return str\r
-\r
- # We have to assume that we must decode this string.\r
- # Down to work.\r
-\r
- # Remove the "s\r
- str = str[1:-1]\r
-\r
- # Check for special sequences. Examples:\r
- # \012 --> \n\r
- # \" --> "\r
- #\r
- i = 0\r
- n = len(str)\r
- res = []\r
- while 0 <= i < n:\r
- Omatch = _OctalPatt.search(str, i)\r
- Qmatch = _QuotePatt.search(str, i)\r
- if not Omatch and not Qmatch: # Neither matched\r
- res.append(str[i:])\r
- break\r
- # else:\r
- j = k = -1\r
- if Omatch: j = Omatch.start(0)\r
- if Qmatch: k = Qmatch.start(0)\r
- if Qmatch and ( not Omatch or k < j ): # QuotePatt matched\r
- res.append(str[i:k])\r
- res.append(str[k+1])\r
- i = k+2\r
- else: # OctalPatt matched\r
- res.append(str[i:j])\r
- res.append( chr( int(str[j+1:j+4], 8) ) )\r
- i = j+4\r
- return _nulljoin(res)\r
-# end _unquote\r
-\r
-# The _getdate() routine is used to set the expiration time in\r
-# the cookie's HTTP header. By default, _getdate() returns the\r
-# current time in the appropriate "expires" format for a\r
-# Set-Cookie header. The one optional argument is an offset from\r
-# now, in seconds. For example, an offset of -3600 means "one hour ago".\r
-# The offset may be a floating point number.\r
-#\r
-\r
-_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\r
-\r
-_monthname = [None,\r
- 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',\r
- 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']\r
-\r
-def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):\r
- from time import gmtime, time\r
- now = time()\r
- year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)\r
- return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \\r
- (weekdayname[wd], day, monthname[month], year, hh, mm, ss)\r
-\r
-\r
-#\r
-# A class to hold ONE key,value pair.\r
-# In a cookie, each such pair may have several attributes.\r
-# so this class is used to keep the attributes associated\r
-# with the appropriate key,value pair.\r
-# This class also includes a coded_value attribute, which\r
-# is used to hold the network representation of the\r
-# value. This is most useful when Python objects are\r
-# pickled for network transit.\r
-#\r
-\r
-class Morsel(dict):\r
- # RFC 2109 lists these attributes as reserved:\r
- # path comment domain\r
- # max-age secure version\r
- #\r
- # For historical reasons, these attributes are also reserved:\r
- # expires\r
- #\r
- # This is an extension from Microsoft:\r
- # httponly\r
- #\r
- # This dictionary provides a mapping from the lowercase\r
- # variant on the left to the appropriate traditional\r
- # formatting on the right.\r
- _reserved = { "expires" : "expires",\r
- "path" : "Path",\r
- "comment" : "Comment",\r
- "domain" : "Domain",\r
- "max-age" : "Max-Age",\r
- "secure" : "secure",\r
- "httponly" : "httponly",\r
- "version" : "Version",\r
- }\r
-\r
- def __init__(self):\r
- # Set defaults\r
- self.key = self.value = self.coded_value = None\r
-\r
- # Set default attributes\r
- for K in self._reserved:\r
- dict.__setitem__(self, K, "")\r
- # end __init__\r
-\r
- def __setitem__(self, K, V):\r
- K = K.lower()\r
- if not K in self._reserved:\r
- raise CookieError("Invalid Attribute %s" % K)\r
- dict.__setitem__(self, K, V)\r
- # end __setitem__\r
-\r
- def isReservedKey(self, K):\r
- return K.lower() in self._reserved\r
- # end isReservedKey\r
-\r
- def set(self, key, val, coded_val,\r
- LegalChars=_LegalChars,\r
- idmap=_idmap, translate=string.translate):\r
- # First we verify that the key isn't a reserved word\r
- # Second we make sure it only contains legal characters\r
- if key.lower() in self._reserved:\r
- raise CookieError("Attempt to set a reserved key: %s" % key)\r
- if "" != translate(key, idmap, LegalChars):\r
- raise CookieError("Illegal key value: %s" % key)\r
-\r
- # It's a good key, so save it.\r
- self.key = key\r
- self.value = val\r
- self.coded_value = coded_val\r
- # end set\r
-\r
- def output(self, attrs=None, header = "Set-Cookie:"):\r
- return "%s %s" % ( header, self.OutputString(attrs) )\r
-\r
- __str__ = output\r
-\r
- def __repr__(self):\r
- return '<%s: %s=%s>' % (self.__class__.__name__,\r
- self.key, repr(self.value) )\r
-\r
- def js_output(self, attrs=None):\r
- # Print javascript\r
- return """\r
- <script type="text/javascript">\r
- <!-- begin hiding\r
- document.cookie = \"%s\";\r
- // end hiding -->\r
- </script>\r
- """ % ( self.OutputString(attrs).replace('"',r'\"'), )\r
- # end js_output()\r
-\r
- def OutputString(self, attrs=None):\r
- # Build up our result\r
- #\r
- result = []\r
- RA = result.append\r
-\r
- # First, the key=value pair\r
- RA("%s=%s" % (self.key, self.coded_value))\r
-\r
- # Now add any defined attributes\r
- if attrs is None:\r
- attrs = self._reserved\r
- items = self.items()\r
- items.sort()\r
- for K,V in items:\r
- if V == "": continue\r
- if K not in attrs: continue\r
- if K == "expires" and type(V) == type(1):\r
- RA("%s=%s" % (self._reserved[K], _getdate(V)))\r
- elif K == "max-age" and type(V) == type(1):\r
- RA("%s=%d" % (self._reserved[K], V))\r
- elif K == "secure":\r
- RA(str(self._reserved[K]))\r
- elif K == "httponly":\r
- RA(str(self._reserved[K]))\r
- else:\r
- RA("%s=%s" % (self._reserved[K], V))\r
-\r
- # Return the result\r
- return _semispacejoin(result)\r
- # end OutputString\r
-# end Morsel class\r
-\r
-\r
-\r
-#\r
-# Pattern for finding cookie\r
-#\r
-# This used to be strict parsing based on the RFC2109 and RFC2068\r
-# specifications. I have since discovered that MSIE 3.0x doesn't\r
-# follow the character rules outlined in those specs. As a\r
-# result, the parsing rules here are less strict.\r
-#\r
-\r
-_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"\r
-_CookiePattern = re.compile(\r
- r"(?x)" # This is a Verbose pattern\r
- r"(?P<key>" # Start of group 'key'\r
- ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy\r
- r")" # End of group 'key'\r
- r"\s*=\s*" # Equal Sign\r
- r"(?P<val>" # Start of group 'val'\r
- r'"(?:[^\\"]|\\.)*"' # Any doublequoted string\r
- r"|" # or\r
- r"\w{3},\s[\w\d-]{9,11}\s[\d:]{8}\sGMT" # Special case for "expires" attr\r
- r"|" # or\r
- ""+ _LegalCharsPatt +"*" # Any word or empty string\r
- r")" # End of group 'val'\r
- r"\s*;?" # Probably ending in a semi-colon\r
- )\r
-\r
-\r
-# At long last, here is the cookie class.\r
-# Using this class is almost just like using a dictionary.\r
-# See this module's docstring for example usage.\r
-#\r
-class BaseCookie(dict):\r
- # A container class for a set of Morsels\r
- #\r
-\r
- def value_decode(self, val):\r
- """real_value, coded_value = value_decode(STRING)\r
- Called prior to setting a cookie's value from the network\r
- representation. The VALUE is the value read from HTTP\r
- header.\r
- Override this function to modify the behavior of cookies.\r
- """\r
- return val, val\r
- # end value_encode\r
-\r
- def value_encode(self, val):\r
- """real_value, coded_value = value_encode(VALUE)\r
- Called prior to setting a cookie's value from the dictionary\r
- representation. The VALUE is the value being assigned.\r
- Override this function to modify the behavior of cookies.\r
- """\r
- strval = str(val)\r
- return strval, strval\r
- # end value_encode\r
-\r
- def __init__(self, input=None):\r
- if input: self.load(input)\r
- # end __init__\r
-\r
- def __set(self, key, real_value, coded_value):\r
- """Private method for setting a cookie's value"""\r
- M = self.get(key, Morsel())\r
- M.set(key, real_value, coded_value)\r
- dict.__setitem__(self, key, M)\r
- # end __set\r
-\r
- def __setitem__(self, key, value):\r
- """Dictionary style assignment."""\r
- rval, cval = self.value_encode(value)\r
- self.__set(key, rval, cval)\r
- # end __setitem__\r
-\r
- def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):\r
- """Return a string suitable for HTTP."""\r
- result = []\r
- items = self.items()\r
- items.sort()\r
- for K,V in items:\r
- result.append( V.output(attrs, header) )\r
- return sep.join(result)\r
- # end output\r
-\r
- __str__ = output\r
-\r
- def __repr__(self):\r
- L = []\r
- items = self.items()\r
- items.sort()\r
- for K,V in items:\r
- L.append( '%s=%s' % (K,repr(V.value) ) )\r
- return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))\r
-\r
- def js_output(self, attrs=None):\r
- """Return a string suitable for JavaScript."""\r
- result = []\r
- items = self.items()\r
- items.sort()\r
- for K,V in items:\r
- result.append( V.js_output(attrs) )\r
- return _nulljoin(result)\r
- # end js_output\r
-\r
- def load(self, rawdata):\r
- """Load cookies from a string (presumably HTTP_COOKIE) or\r
- from a dictionary. Loading cookies from a dictionary 'd'\r
- is equivalent to calling:\r
- map(Cookie.__setitem__, d.keys(), d.values())\r
- """\r
- if type(rawdata) == type(""):\r
- self.__ParseString(rawdata)\r
- else:\r
- # self.update() wouldn't call our custom __setitem__\r
- for k, v in rawdata.items():\r
- self[k] = v\r
- return\r
- # end load()\r
-\r
- def __ParseString(self, str, patt=_CookiePattern):\r
- i = 0 # Our starting point\r
- n = len(str) # Length of string\r
- M = None # current morsel\r
-\r
- while 0 <= i < n:\r
- # Start looking for a cookie\r
- match = patt.search(str, i)\r
- if not match: break # No more cookies\r
-\r
- K,V = match.group("key"), match.group("val")\r
- i = match.end(0)\r
-\r
- # Parse the key, value in case it's metainfo\r
- if K[0] == "$":\r
- # We ignore attributes which pertain to the cookie\r
- # mechanism as a whole. See RFC 2109.\r
- # (Does anyone care?)\r
- if M:\r
- M[ K[1:] ] = V\r
- elif K.lower() in Morsel._reserved:\r
- if M:\r
- M[ K ] = _unquote(V)\r
- else:\r
- rval, cval = self.value_decode(V)\r
- self.__set(K, rval, cval)\r
- M = self[K]\r
- # end __ParseString\r
-# end BaseCookie class\r
-\r
-class SimpleCookie(BaseCookie):\r
- """SimpleCookie\r
- SimpleCookie supports strings as cookie values. When setting\r
- the value using the dictionary assignment notation, SimpleCookie\r
- calls the builtin str() to convert the value to a string. Values\r
- received from HTTP are kept as strings.\r
- """\r
- def value_decode(self, val):\r
- return _unquote( val ), val\r
- def value_encode(self, val):\r
- strval = str(val)\r
- return strval, _quote( strval )\r
-# end SimpleCookie\r
-\r
-class SerialCookie(BaseCookie):\r
- """SerialCookie\r
- SerialCookie supports arbitrary objects as cookie values. All\r
- values are serialized (using cPickle) before being sent to the\r
- client. All incoming values are assumed to be valid Pickle\r
- representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE\r
- FORMAT, THEN AN EXCEPTION WILL BE RAISED.\r
-\r
- Note: Large cookie values add overhead because they must be\r
- retransmitted on every HTTP transaction.\r
-\r
- Note: HTTP has a 2k limit on the size of a cookie. This class\r
- does not check for this limit, so be careful!!!\r
- """\r
- def __init__(self, input=None):\r
- warnings.warn("SerialCookie class is insecure; do not use it",\r
- DeprecationWarning)\r
- BaseCookie.__init__(self, input)\r
- # end __init__\r
- def value_decode(self, val):\r
- # This could raise an exception!\r
- return loads( _unquote(val) ), val\r
- def value_encode(self, val):\r
- return val, _quote( dumps(val) )\r
-# end SerialCookie\r
-\r
-class SmartCookie(BaseCookie):\r
- """SmartCookie\r
- SmartCookie supports arbitrary objects as cookie values. If the\r
- object is a string, then it is quoted. If the object is not a\r
- string, however, then SmartCookie will use cPickle to serialize\r
- the object into a string representation.\r
-\r
- Note: Large cookie values add overhead because they must be\r
- retransmitted on every HTTP transaction.\r
-\r
- Note: HTTP has a 2k limit on the size of a cookie. This class\r
- does not check for this limit, so be careful!!!\r
- """\r
- def __init__(self, input=None):\r
- warnings.warn("Cookie/SmartCookie class is insecure; do not use it",\r
- DeprecationWarning)\r
- BaseCookie.__init__(self, input)\r
- # end __init__\r
- def value_decode(self, val):\r
- strval = _unquote(val)\r
- try:\r
- return loads(strval), val\r
- except:\r
- return strval, val\r
- def value_encode(self, val):\r
- if type(val) == type(""):\r
- return val, _quote(val)\r
- else:\r
- return val, _quote( dumps(val) )\r
-# end SmartCookie\r
-\r
-\r
-###########################################################\r
-# Backwards Compatibility: Don't break any existing code!\r
-\r
-# We provide Cookie() as an alias for SmartCookie()\r
-Cookie = SmartCookie\r
-\r
-#\r
-###########################################################\r
-\r
-def _test():\r
- import doctest, Cookie\r
- return doctest.testmod(Cookie)\r
-\r
-if __name__ == "__main__":\r
- _test()\r
-\r
-\r
-#Local Variables:\r
-#tab-width: 4\r
-#end:\r