0001 #!/usr/bin/env python 0002 # 0003 0004 #### 0005 # Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu> 0006 # 0007 # All Rights Reserved 0008 # 0009 # Permission to use, copy, modify, and distribute this software 0010 # and its documentation for any purpose and without fee is hereby 0011 # granted, provided that the above copyright notice appear in all 0012 # copies and that both that copyright notice and this permission 0013 # notice appear in supporting documentation, and that the name of 0014 # Timothy O'Malley not be used in advertising or publicity 0015 # pertaining to distribution of the software without specific, written 0016 # prior permission. 0017 # 0018 # Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 0019 # SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 0020 # AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR 0021 # ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 0022 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 0023 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 0024 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 0025 # PERFORMANCE OF THIS SOFTWARE. 0026 # 0027 #### 0028 # 0029 # Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp 0030 # by Timothy O'Malley <timo@alum.mit.edu> 0031 # 0032 # Cookie.py is a Python module for the handling of HTTP 0033 # cookies as a Python dictionary. See RFC 2109 for more 0034 # information on cookies. 0035 # 0036 # The original idea to treat Cookies as a dictionary came from 0037 # Dave Mitchell (davem@magnet.com) in 1995, when he released the 0038 # first version of nscookie.py. 0039 # 0040 #### 0041 0042 r""" 0043 Here's a sample session to show how to use this module. 0044 At the moment, this is the only documentation. 0045 0046 The Basics 0047 ---------- 0048 0049 Importing is easy.. 0050 0051 >>> import Cookie 0052 0053 Most of the time you start by creating a cookie. Cookies come in 0054 three flavors, each with slightly different encoding semantics, but 0055 more on that later. 0056 0057 >>> C = Cookie.SimpleCookie() 0058 >>> C = Cookie.SerialCookie() 0059 >>> C = Cookie.SmartCookie() 0060 0061 [Note: Long-time users of Cookie.py will remember using 0062 Cookie.Cookie() to create an Cookie object. Although deprecated, it 0063 is still supported by the code. See the Backward Compatibility notes 0064 for more information.] 0065 0066 Once you've created your Cookie, you can add values just as if it were 0067 a dictionary. 0068 0069 >>> C = Cookie.SmartCookie() 0070 >>> C["fig"] = "newton" 0071 >>> C["sugar"] = "wafer" 0072 >>> print C 0073 Set-Cookie: fig=newton; 0074 Set-Cookie: sugar=wafer; 0075 0076 Notice that the printable representation of a Cookie is the 0077 appropriate format for a Set-Cookie: header. This is the 0078 default behavior. You can change the header and printed 0079 attributes by using the .output() function 0080 0081 >>> C = Cookie.SmartCookie() 0082 >>> C["rocky"] = "road" 0083 >>> C["rocky"]["path"] = "/cookie" 0084 >>> print C.output(header="Cookie:") 0085 Cookie: rocky=road; Path=/cookie; 0086 >>> print C.output(attrs=[], header="Cookie:") 0087 Cookie: rocky=road; 0088 0089 The load() method of a Cookie extracts cookies from a string. In a 0090 CGI script, you would use this method to extract the cookies from the 0091 HTTP_COOKIE environment variable. 0092 0093 >>> C = Cookie.SmartCookie() 0094 >>> C.load("chips=ahoy; vienna=finger") 0095 >>> print C 0096 Set-Cookie: chips=ahoy; 0097 Set-Cookie: vienna=finger; 0098 0099 The load() method is darn-tootin smart about identifying cookies 0100 within a string. Escaped quotation marks, nested semicolons, and other 0101 such trickeries do not confuse it. 0102 0103 >>> C = Cookie.SmartCookie() 0104 >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') 0105 >>> print C 0106 Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"; 0107 0108 Each element of the Cookie also supports all of the RFC 2109 0109 Cookie attributes. Here's an example which sets the Path 0110 attribute. 0111 0112 >>> C = Cookie.SmartCookie() 0113 >>> C["oreo"] = "doublestuff" 0114 >>> C["oreo"]["path"] = "/" 0115 >>> print C 0116 Set-Cookie: oreo=doublestuff; Path=/; 0117 0118 Each dictionary element has a 'value' attribute, which gives you 0119 back the value associated with the key. 0120 0121 >>> C = Cookie.SmartCookie() 0122 >>> C["twix"] = "none for you" 0123 >>> C["twix"].value 0124 'none for you' 0125 0126 0127 A Bit More Advanced 0128 ------------------- 0129 0130 As mentioned before, there are three different flavors of Cookie 0131 objects, each with different encoding/decoding semantics. This 0132 section briefly discusses the differences. 0133 0134 SimpleCookie 0135 0136 The SimpleCookie expects that all values should be standard strings. 0137 Just to be sure, SimpleCookie invokes the str() builtin to convert 0138 the value to a string, when the values are set dictionary-style. 0139 0140 >>> C = Cookie.SimpleCookie() 0141 >>> C["number"] = 7 0142 >>> C["string"] = "seven" 0143 >>> C["number"].value 0144 '7' 0145 >>> C["string"].value 0146 'seven' 0147 >>> print C 0148 Set-Cookie: number=7; 0149 Set-Cookie: string=seven; 0150 0151 0152 SerialCookie 0153 0154 The SerialCookie expects that all values should be serialized using 0155 cPickle (or pickle, if cPickle isn't available). As a result of 0156 serializing, SerialCookie can save almost any Python object to a 0157 value, and recover the exact same object when the cookie has been 0158 returned. (SerialCookie can yield some strange-looking cookie 0159 values, however.) 0160 0161 >>> C = Cookie.SerialCookie() 0162 >>> C["number"] = 7 0163 >>> C["string"] = "seven" 0164 >>> C["number"].value 0165 7 0166 >>> C["string"].value 0167 'seven' 0168 >>> print C 0169 Set-Cookie: number="I7\012."; 0170 Set-Cookie: string="S'seven'\012p1\012."; 0171 0172 Be warned, however, if SerialCookie cannot de-serialize a value (because 0173 it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION. 0174 0175 0176 SmartCookie 0177 0178 The SmartCookie combines aspects of each of the other two flavors. 0179 When setting a value in a dictionary-fashion, the SmartCookie will 0180 serialize (ala cPickle) the value *if and only if* it isn't a 0181 Python string. String objects are *not* serialized. Similarly, 0182 when the load() method parses out values, it attempts to de-serialize 0183 the value. If it fails, then it fallsback to treating the value 0184 as a string. 0185 0186 >>> C = Cookie.SmartCookie() 0187 >>> C["number"] = 7 0188 >>> C["string"] = "seven" 0189 >>> C["number"].value 0190 7 0191 >>> C["string"].value 0192 'seven' 0193 >>> print C 0194 Set-Cookie: number="I7\012."; 0195 Set-Cookie: string=seven; 0196 0197 0198 Backwards Compatibility 0199 ----------------------- 0200 0201 In order to keep compatibilty with earlier versions of Cookie.py, 0202 it is still possible to use Cookie.Cookie() to create a Cookie. In 0203 fact, this simply returns a SmartCookie. 0204 0205 >>> C = Cookie.Cookie() 0206 >>> print C.__class__.__name__ 0207 SmartCookie 0208 0209 0210 Finis. 0211 """ #" 0212 # ^ 0213 # |----helps out font-lock 0214 0215 # 0216 # Import our required modules 0217 # 0218 import string 0219 0220 try: 0221 from cPickle import dumps, loads 0222 except ImportError: 0223 from pickle import dumps, loads 0224 0225 import re, warnings 0226 0227 __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie", 0228 "SmartCookie","Cookie"] 0229 0230 _nulljoin = ''.join 0231 _spacejoin = ' '.join 0232 0233 # 0234 # Define an exception visible to External modules 0235 # 0236 class CookieError(Exception): 0237 pass 0238 0239 0240 # These quoting routines conform to the RFC2109 specification, which in 0241 # turn references the character definitions from RFC2068. They provide 0242 # a two-way quoting algorithm. Any non-text character is translated 0243 # into a 4 character sequence: a forward-slash followed by the 0244 # three-digit octal equivalent of the character. Any '\' or '"' is 0245 # quoted with a preceeding '\' slash. 0246 # 0247 # These are taken from RFC2068 and RFC2109. 0248 # _LegalChars is the list of chars which don't require "'s 0249 # _Translator hash-table for fast quoting 0250 # 0251 _LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~" 0252 _Translator = { 0253 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002', 0254 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005', 0255 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010', 0256 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013', 0257 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016', 0258 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021', 0259 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024', 0260 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027', 0261 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032', 0262 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035', 0263 '\036' : '\\036', '\037' : '\\037', 0264 0265 '"' : '\\"', '\\' : '\\\\', 0266 0267 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201', 0268 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204', 0269 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207', 0270 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212', 0271 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215', 0272 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220', 0273 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223', 0274 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226', 0275 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231', 0276 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234', 0277 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237', 0278 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242', 0279 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245', 0280 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250', 0281 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253', 0282 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256', 0283 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261', 0284 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264', 0285 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267', 0286 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272', 0287 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275', 0288 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300', 0289 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303', 0290 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306', 0291 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311', 0292 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314', 0293 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317', 0294 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322', 0295 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325', 0296 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330', 0297 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333', 0298 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336', 0299 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341', 0300 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344', 0301 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347', 0302 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352', 0303 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355', 0304 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360', 0305 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363', 0306 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366', 0307 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371', 0308 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374', 0309 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377' 0310 } 0311 0312 def _quote(str, LegalChars=_LegalChars, 0313 idmap=string._idmap, translate=string.translate): 0314 # 0315 # If the string does not need to be double-quoted, 0316 # then just return the string. Otherwise, surround 0317 # the string in doublequotes and precede quote (with a \) 0318 # special characters. 0319 # 0320 if "" == translate(str, idmap, LegalChars): 0321 return str 0322 else: 0323 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"' 0324 # end _quote 0325 0326 0327 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]") 0328 _QuotePatt = re.compile(r"[\\].") 0329 0330 def _unquote(str): 0331 # If there aren't any doublequotes, 0332 # then there can't be any special characters. See RFC 2109. 0333 if len(str) < 2: 0334 return str 0335 if str[0] != '"' or str[-1] != '"': 0336 return str 0337 0338 # We have to assume that we must decode this string. 0339 # Down to work. 0340 0341 # Remove the "s 0342 str = str[1:-1] 0343 0344 # Check for special sequences. Examples: 0345 # \012 --> \n 0346 # \" --> " 0347 # 0348 i = 0 0349 n = len(str) 0350 res = [] 0351 while 0 <= i < n: 0352 Omatch = _OctalPatt.search(str, i) 0353 Qmatch = _QuotePatt.search(str, i) 0354 if not Omatch and not Qmatch: # Neither matched 0355 res.append(str[i:]) 0356 break 0357 # else: 0358 j = k = -1 0359 if Omatch: j = Omatch.start(0) 0360 if Qmatch: k = Qmatch.start(0) 0361 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched 0362 res.append(str[i:k]) 0363 res.append(str[k+1]) 0364 i = k+2 0365 else: # OctalPatt matched 0366 res.append(str[i:j]) 0367 res.append( chr( int(str[j+1:j+4], 8) ) ) 0368 i = j+4 0369 return _nulljoin(res) 0370 # end _unquote 0371 0372 # The _getdate() routine is used to set the expiration time in 0373 # the cookie's HTTP header. By default, _getdate() returns the 0374 # current time in the appropriate "expires" format for a 0375 # Set-Cookie header. The one optional argument is an offset from 0376 # now, in seconds. For example, an offset of -3600 means "one hour ago". 0377 # The offset may be a floating point number. 0378 # 0379 0380 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] 0381 0382 _monthname = [None, 0383 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 0384 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 0385 0386 def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname): 0387 from time import gmtime, time 0388 now = time() 0389 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future) 0390 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \ 0391 (weekdayname[wd], day, monthname[month], year, hh, mm, ss) 0392 0393 0394 # 0395 # A class to hold ONE key,value pair. 0396 # In a cookie, each such pair may have several attributes. 0397 # so this class is used to keep the attributes associated 0398 # with the appropriate key,value pair. 0399 # This class also includes a coded_value attribute, which 0400 # is used to hold the network representation of the 0401 # value. This is most useful when Python objects are 0402 # pickled for network transit. 0403 # 0404 0405 class Morsel(dict): 0406 # RFC 2109 lists these attributes as reserved: 0407 # path comment domain 0408 # max-age secure version 0409 # 0410 # For historical reasons, these attributes are also reserved: 0411 # expires 0412 # 0413 # This dictionary provides a mapping from the lowercase 0414 # variant on the left to the appropriate traditional 0415 # formatting on the right. 0416 _reserved = { "expires" : "expires", 0417 "path" : "Path", 0418 "comment" : "Comment", 0419 "domain" : "Domain", 0420 "max-age" : "Max-Age", 0421 "secure" : "secure", 0422 "version" : "Version", 0423 } 0424 0425 def __init__(self): 0426 # Set defaults 0427 self.key = self.value = self.coded_value = None 0428 0429 # Set default attributes 0430 for K in self._reserved: 0431 dict.__setitem__(self, K, "") 0432 # end __init__ 0433 0434 def __setitem__(self, K, V): 0435 K = K.lower() 0436 if not K in self._reserved: 0437 raise CookieError("Invalid Attribute %s" % K) 0438 dict.__setitem__(self, K, V) 0439 # end __setitem__ 0440 0441 def isReservedKey(self, K): 0442 return K.lower() in self._reserved 0443 # end isReservedKey 0444 0445 def set(self, key, val, coded_val, 0446 LegalChars=_LegalChars, 0447 idmap=string._idmap, translate=string.translate ): 0448 # First we verify that the key isn't a reserved word 0449 # Second we make sure it only contains legal characters 0450 if key.lower() in self._reserved: 0451 raise CookieError("Attempt to set a reserved key: %s" % key) 0452 if "" != translate(key, idmap, LegalChars): 0453 raise CookieError("Illegal key value: %s" % key) 0454 0455 # It's a good key, so save it. 0456 self.key = key 0457 self.value = val 0458 self.coded_value = coded_val 0459 # end set 0460 0461 def output(self, attrs=None, header = "Set-Cookie:"): 0462 return "%s %s" % ( header, self.OutputString(attrs) ) 0463 0464 __str__ = output 0465 0466 def __repr__(self): 0467 return '<%s: %s=%s>' % (self.__class__.__name__, 0468 self.key, repr(self.value) ) 0469 0470 def js_output(self, attrs=None): 0471 # Print javascript 0472 return """ 0473 <SCRIPT LANGUAGE="JavaScript"> 0474 <!-- begin hiding 0475 document.cookie = \"%s\" 0476 // end hiding --> 0477 </script> 0478 """ % ( self.OutputString(attrs), ) 0479 # end js_output() 0480 0481 def OutputString(self, attrs=None): 0482 # Build up our result 0483 # 0484 result = [] 0485 RA = result.append 0486 0487 # First, the key=value pair 0488 RA("%s=%s;" % (self.key, self.coded_value)) 0489 0490 # Now add any defined attributes 0491 if attrs is None: 0492 attrs = self._reserved 0493 items = self.items() 0494 items.sort() 0495 for K,V in items: 0496 if V == "": continue 0497 if K not in attrs: continue 0498 if K == "expires" and type(V) == type(1): 0499 RA("%s=%s;" % (self._reserved[K], _getdate(V))) 0500 elif K == "max-age" and type(V) == type(1): 0501 RA("%s=%d;" % (self._reserved[K], V)) 0502 elif K == "secure": 0503 RA("%s;" % self._reserved[K]) 0504 else: 0505 RA("%s=%s;" % (self._reserved[K], V)) 0506 0507 # Return the result 0508 return _spacejoin(result) 0509 # end OutputString 0510 # end Morsel class 0511 0512 0513 0514 # 0515 # Pattern for finding cookie 0516 # 0517 # This used to be strict parsing based on the RFC2109 and RFC2068 0518 # specifications. I have since discovered that MSIE 3.0x doesn't 0519 # follow the character rules outlined in those specs. As a 0520 # result, the parsing rules here are less strict. 0521 # 0522 0523 _LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]" 0524 _CookiePattern = re.compile( 0525 r"(?x)" # This is a Verbose pattern 0526 r"(?P<key>" # Start of group 'key' 0527 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy 0528 r")" # End of group 'key' 0529 r"\s*=\s*" # Equal Sign 0530 r"(?P<val>" # Start of group 'val' 0531 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string 0532 r"|" # or 0533 ""+ _LegalCharsPatt +"*" # Any word or empty string 0534 r")" # End of group 'val' 0535 r"\s*;?" # Probably ending in a semi-colon 0536 ) 0537 0538 0539 # At long last, here is the cookie class. 0540 # Using this class is almost just like using a dictionary. 0541 # See this module's docstring for example usage. 0542 # 0543 class BaseCookie(dict): 0544 # A container class for a set of Morsels 0545 # 0546 0547 def value_decode(self, val): 0548 """real_value, coded_value = value_decode(STRING) 0549 Called prior to setting a cookie's value from the network 0550 representation. The VALUE is the value read from HTTP 0551 header. 0552 Override this function to modify the behavior of cookies. 0553 """ 0554 return val, val 0555 # end value_encode 0556 0557 def value_encode(self, val): 0558 """real_value, coded_value = value_encode(VALUE) 0559 Called prior to setting a cookie's value from the dictionary 0560 representation. The VALUE is the value being assigned. 0561 Override this function to modify the behavior of cookies. 0562 """ 0563 strval = str(val) 0564 return strval, strval 0565 # end value_encode 0566 0567 def __init__(self, input=None): 0568 if input: self.load(input) 0569 # end __init__ 0570 0571 def __set(self, key, real_value, coded_value): 0572 """Private method for setting a cookie's value""" 0573 M = self.get(key, Morsel()) 0574 M.set(key, real_value, coded_value) 0575 dict.__setitem__(self, key, M) 0576 # end __set 0577 0578 def __setitem__(self, key, value): 0579 """Dictionary style assignment.""" 0580 rval, cval = self.value_encode(value) 0581 self.__set(key, rval, cval) 0582 # end __setitem__ 0583 0584 def output(self, attrs=None, header="Set-Cookie:", sep="\n"): 0585 """Return a string suitable for HTTP.""" 0586 result = [] 0587 items = self.items() 0588 items.sort() 0589 for K,V in items: 0590 result.append( V.output(attrs, header) ) 0591 return sep.join(result) 0592 # end output 0593 0594 __str__ = output 0595 0596 def __repr__(self): 0597 L = [] 0598 items = self.items() 0599 items.sort() 0600 for K,V in items: 0601 L.append( '%s=%s' % (K,repr(V.value) ) ) 0602 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L)) 0603 0604 def js_output(self, attrs=None): 0605 """Return a string suitable for JavaScript.""" 0606 result = [] 0607 items = self.items() 0608 items.sort() 0609 for K,V in items: 0610 result.append( V.js_output(attrs) ) 0611 return _nulljoin(result) 0612 # end js_output 0613 0614 def load(self, rawdata): 0615 """Load cookies from a string (presumably HTTP_COOKIE) or 0616 from a dictionary. Loading cookies from a dictionary 'd' 0617 is equivalent to calling: 0618 map(Cookie.__setitem__, d.keys(), d.values()) 0619 """ 0620 if type(rawdata) == type(""): 0621 self.__ParseString(rawdata) 0622 else: 0623 self.update(rawdata) 0624 return 0625 # end load() 0626 0627 def __ParseString(self, str, patt=_CookiePattern): 0628 i = 0 # Our starting point 0629 n = len(str) # Length of string 0630 M = None # current morsel 0631 0632 while 0 <= i < n: 0633 # Start looking for a cookie 0634 match = patt.search(str, i) 0635 if not match: break # No more cookies 0636 0637 K,V = match.group("key"), match.group("val") 0638 i = match.end(0) 0639 0640 # Parse the key, value in case it's metainfo 0641 if K[0] == "$": 0642 # We ignore attributes which pertain to the cookie 0643 # mechanism as a whole. See RFC 2109. 0644 # (Does anyone care?) 0645 if M: 0646 M[ K[1:] ] = V 0647 elif K.lower() in Morsel._reserved: 0648 if M: 0649 M[ K ] = _unquote(V) 0650 else: 0651 rval, cval = self.value_decode(V) 0652 self.__set(K, rval, cval) 0653 M = self[K] 0654 # end __ParseString 0655 # end BaseCookie class 0656 0657 class SimpleCookie(BaseCookie): 0658 """SimpleCookie 0659 SimpleCookie supports strings as cookie values. When setting 0660 the value using the dictionary assignment notation, SimpleCookie 0661 calls the builtin str() to convert the value to a string. Values 0662 received from HTTP are kept as strings. 0663 """ 0664 def value_decode(self, val): 0665 return _unquote( val ), val 0666 def value_encode(self, val): 0667 strval = str(val) 0668 return strval, _quote( strval ) 0669 # end SimpleCookie 0670 0671 class SerialCookie(BaseCookie): 0672 """SerialCookie 0673 SerialCookie supports arbitrary objects as cookie values. All 0674 values are serialized (using cPickle) before being sent to the 0675 client. All incoming values are assumed to be valid Pickle 0676 representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE 0677 FORMAT, THEN AN EXCEPTION WILL BE RAISED. 0678 0679 Note: Large cookie values add overhead because they must be 0680 retransmitted on every HTTP transaction. 0681 0682 Note: HTTP has a 2k limit on the size of a cookie. This class 0683 does not check for this limit, so be careful!!! 0684 """ 0685 def __init__(self, input=None): 0686 warnings.warn("SerialCookie class is insecure; do not use it", 0687 DeprecationWarning) 0688 BaseCookie.__init__(self, input) 0689 # end __init__ 0690 def value_decode(self, val): 0691 # This could raise an exception! 0692 return loads( _unquote(val) ), val 0693 def value_encode(self, val): 0694 return val, _quote( dumps(val) ) 0695 # end SerialCookie 0696 0697 class SmartCookie(BaseCookie): 0698 """SmartCookie 0699 SmartCookie supports arbitrary objects as cookie values. If the 0700 object is a string, then it is quoted. If the object is not a 0701 string, however, then SmartCookie will use cPickle to serialize 0702 the object into a string representation. 0703 0704 Note: Large cookie values add overhead because they must be 0705 retransmitted on every HTTP transaction. 0706 0707 Note: HTTP has a 2k limit on the size of a cookie. This class 0708 does not check for this limit, so be careful!!! 0709 """ 0710 def __init__(self, input=None): 0711 warnings.warn("Cookie/SmartCookie class is insecure; do not use it", 0712 DeprecationWarning) 0713 BaseCookie.__init__(self, input) 0714 # end __init__ 0715 def value_decode(self, val): 0716 strval = _unquote(val) 0717 try: 0718 return loads(strval), val 0719 except: 0720 return strval, val 0721 def value_encode(self, val): 0722 if type(val) == type(""): 0723 return val, _quote(val) 0724 else: 0725 return val, _quote( dumps(val) ) 0726 # end SmartCookie 0727 0728 0729 ########################################################### 0730 # Backwards Compatibility: Don't break any existing code! 0731 0732 # We provide Cookie() as an alias for SmartCookie() 0733 Cookie = SmartCookie 0734 0735 # 0736 ########################################################### 0737 0738 def _test(): 0739 import doctest, Cookie 0740 return doctest.testmod(Cookie) 0741 0742 if __name__ == "__main__": 0743 _test() 0744 0745 0746 #Local Variables: 0747 #tab-width: 4 0748 #end: 0749
Generated by PyXR 0.9.4