Minor documentation changes cross-referencing NullHandler to the documentation on...
[python.git] / Lib / Cookie.py
blobb2f7427aa94f734ab2a34285917fb11eb0b2c4fc
1 #!/usr/bin/env python
4 ####
5 # Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
7 # All Rights Reserved
9 # Permission to use, copy, modify, and distribute this software
10 # and its documentation for any purpose and without fee is hereby
11 # granted, provided that the above copyright notice appear in all
12 # copies and that both that copyright notice and this permission
13 # notice appear in supporting documentation, and that the name of
14 # Timothy O'Malley not be used in advertising or publicity
15 # pertaining to distribution of the software without specific, written
16 # prior permission.
18 # Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
19 # SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20 # AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
21 # ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
24 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25 # PERFORMANCE OF THIS SOFTWARE.
27 ####
29 # Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
30 # by Timothy O'Malley <timo@alum.mit.edu>
32 # Cookie.py is a Python module for the handling of HTTP
33 # cookies as a Python dictionary. See RFC 2109 for more
34 # information on cookies.
36 # The original idea to treat Cookies as a dictionary came from
37 # Dave Mitchell (davem@magnet.com) in 1995, when he released the
38 # first version of nscookie.py.
40 ####
42 r"""
43 Here's a sample session to show how to use this module.
44 At the moment, this is the only documentation.
46 The Basics
47 ----------
49 Importing is easy..
51 >>> import Cookie
53 Most of the time you start by creating a cookie. Cookies come in
54 three flavors, each with slightly different encoding semantics, but
55 more on that later.
57 >>> C = Cookie.SimpleCookie()
58 >>> C = Cookie.SerialCookie()
59 >>> C = Cookie.SmartCookie()
61 [Note: Long-time users of Cookie.py will remember using
62 Cookie.Cookie() to create an Cookie object. Although deprecated, it
63 is still supported by the code. See the Backward Compatibility notes
64 for more information.]
66 Once you've created your Cookie, you can add values just as if it were
67 a dictionary.
69 >>> C = Cookie.SmartCookie()
70 >>> C["fig"] = "newton"
71 >>> C["sugar"] = "wafer"
72 >>> C.output()
73 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
75 Notice that the printable representation of a Cookie is the
76 appropriate format for a Set-Cookie: header. This is the
77 default behavior. You can change the header and printed
78 attributes by using the .output() function
80 >>> C = Cookie.SmartCookie()
81 >>> C["rocky"] = "road"
82 >>> C["rocky"]["path"] = "/cookie"
83 >>> print C.output(header="Cookie:")
84 Cookie: rocky=road; Path=/cookie
85 >>> print C.output(attrs=[], header="Cookie:")
86 Cookie: rocky=road
88 The load() method of a Cookie extracts cookies from a string. In a
89 CGI script, you would use this method to extract the cookies from the
90 HTTP_COOKIE environment variable.
92 >>> C = Cookie.SmartCookie()
93 >>> C.load("chips=ahoy; vienna=finger")
94 >>> C.output()
95 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
97 The load() method is darn-tootin smart about identifying cookies
98 within a string. Escaped quotation marks, nested semicolons, and other
99 such trickeries do not confuse it.
101 >>> C = Cookie.SmartCookie()
102 >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
103 >>> print C
104 Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
106 Each element of the Cookie also supports all of the RFC 2109
107 Cookie attributes. Here's an example which sets the Path
108 attribute.
110 >>> C = Cookie.SmartCookie()
111 >>> C["oreo"] = "doublestuff"
112 >>> C["oreo"]["path"] = "/"
113 >>> print C
114 Set-Cookie: oreo=doublestuff; Path=/
116 Each dictionary element has a 'value' attribute, which gives you
117 back the value associated with the key.
119 >>> C = Cookie.SmartCookie()
120 >>> C["twix"] = "none for you"
121 >>> C["twix"].value
122 'none for you'
125 A Bit More Advanced
126 -------------------
128 As mentioned before, there are three different flavors of Cookie
129 objects, each with different encoding/decoding semantics. This
130 section briefly discusses the differences.
132 SimpleCookie
134 The SimpleCookie expects that all values should be standard strings.
135 Just to be sure, SimpleCookie invokes the str() builtin to convert
136 the value to a string, when the values are set dictionary-style.
138 >>> C = Cookie.SimpleCookie()
139 >>> C["number"] = 7
140 >>> C["string"] = "seven"
141 >>> C["number"].value
143 >>> C["string"].value
144 'seven'
145 >>> C.output()
146 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
149 SerialCookie
151 The SerialCookie expects that all values should be serialized using
152 cPickle (or pickle, if cPickle isn't available). As a result of
153 serializing, SerialCookie can save almost any Python object to a
154 value, and recover the exact same object when the cookie has been
155 returned. (SerialCookie can yield some strange-looking cookie
156 values, however.)
158 >>> C = Cookie.SerialCookie()
159 >>> C["number"] = 7
160 >>> C["string"] = "seven"
161 >>> C["number"].value
163 >>> C["string"].value
164 'seven'
165 >>> C.output()
166 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'
168 Be warned, however, if SerialCookie cannot de-serialize a value (because
169 it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
172 SmartCookie
174 The SmartCookie combines aspects of each of the other two flavors.
175 When setting a value in a dictionary-fashion, the SmartCookie will
176 serialize (ala cPickle) the value *if and only if* it isn't a
177 Python string. String objects are *not* serialized. Similarly,
178 when the load() method parses out values, it attempts to de-serialize
179 the value. If it fails, then it fallsback to treating the value
180 as a string.
182 >>> C = Cookie.SmartCookie()
183 >>> C["number"] = 7
184 >>> C["string"] = "seven"
185 >>> C["number"].value
187 >>> C["string"].value
188 'seven'
189 >>> C.output()
190 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
193 Backwards Compatibility
194 -----------------------
196 In order to keep compatibilty with earlier versions of Cookie.py,
197 it is still possible to use Cookie.Cookie() to create a Cookie. In
198 fact, this simply returns a SmartCookie.
200 >>> C = Cookie.Cookie()
201 >>> print C.__class__.__name__
202 SmartCookie
205 Finis.
206 """ #"
208 # |----helps out font-lock
211 # Import our required modules
213 import string
215 try:
216 from cPickle import dumps, loads
217 except ImportError:
218 from pickle import dumps, loads
220 import re, warnings
222 __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
223 "SmartCookie","Cookie"]
225 _nulljoin = ''.join
226 _semispacejoin = '; '.join
227 _spacejoin = ' '.join
230 # Define an exception visible to External modules
232 class CookieError(Exception):
233 pass
236 # These quoting routines conform to the RFC2109 specification, which in
237 # turn references the character definitions from RFC2068. They provide
238 # a two-way quoting algorithm. Any non-text character is translated
239 # into a 4 character sequence: a forward-slash followed by the
240 # three-digit octal equivalent of the character. Any '\' or '"' is
241 # quoted with a preceeding '\' slash.
243 # These are taken from RFC2068 and RFC2109.
244 # _LegalChars is the list of chars which don't require "'s
245 # _Translator hash-table for fast quoting
247 _LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
248 _Translator = {
249 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
250 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
251 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
252 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
253 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
254 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
255 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
256 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
257 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
258 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
259 '\036' : '\\036', '\037' : '\\037',
261 '"' : '\\"', '\\' : '\\\\',
263 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
264 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
265 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
266 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
267 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
268 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
269 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
270 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
271 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
272 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
273 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
274 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
275 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
276 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
277 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
278 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
279 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
280 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
281 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
282 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
283 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
284 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
285 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
286 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
287 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
288 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
289 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
290 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
291 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
292 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
293 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
294 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
295 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
296 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
297 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
298 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
299 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
300 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
301 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
302 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
303 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
304 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
305 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
308 _idmap = ''.join(chr(x) for x in xrange(256))
310 def _quote(str, LegalChars=_LegalChars,
311 idmap=_idmap, translate=string.translate):
313 # If the string does not need to be double-quoted,
314 # then just return the string. Otherwise, surround
315 # the string in doublequotes and precede quote (with a \)
316 # special characters.
318 if "" == translate(str, idmap, LegalChars):
319 return str
320 else:
321 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
322 # end _quote
325 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
326 _QuotePatt = re.compile(r"[\\].")
328 def _unquote(str):
329 # If there aren't any doublequotes,
330 # then there can't be any special characters. See RFC 2109.
331 if len(str) < 2:
332 return str
333 if str[0] != '"' or str[-1] != '"':
334 return str
336 # We have to assume that we must decode this string.
337 # Down to work.
339 # Remove the "s
340 str = str[1:-1]
342 # Check for special sequences. Examples:
343 # \012 --> \n
344 # \" --> "
346 i = 0
347 n = len(str)
348 res = []
349 while 0 <= i < n:
350 Omatch = _OctalPatt.search(str, i)
351 Qmatch = _QuotePatt.search(str, i)
352 if not Omatch and not Qmatch: # Neither matched
353 res.append(str[i:])
354 break
355 # else:
356 j = k = -1
357 if Omatch: j = Omatch.start(0)
358 if Qmatch: k = Qmatch.start(0)
359 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
360 res.append(str[i:k])
361 res.append(str[k+1])
362 i = k+2
363 else: # OctalPatt matched
364 res.append(str[i:j])
365 res.append( chr( int(str[j+1:j+4], 8) ) )
366 i = j+4
367 return _nulljoin(res)
368 # end _unquote
370 # The _getdate() routine is used to set the expiration time in
371 # the cookie's HTTP header. By default, _getdate() returns the
372 # current time in the appropriate "expires" format for a
373 # Set-Cookie header. The one optional argument is an offset from
374 # now, in seconds. For example, an offset of -3600 means "one hour ago".
375 # The offset may be a floating point number.
378 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
380 _monthname = [None,
381 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
382 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
384 def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
385 from time import gmtime, time
386 now = time()
387 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
388 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
389 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
393 # A class to hold ONE key,value pair.
394 # In a cookie, each such pair may have several attributes.
395 # so this class is used to keep the attributes associated
396 # with the appropriate key,value pair.
397 # This class also includes a coded_value attribute, which
398 # is used to hold the network representation of the
399 # value. This is most useful when Python objects are
400 # pickled for network transit.
403 class Morsel(dict):
404 # RFC 2109 lists these attributes as reserved:
405 # path comment domain
406 # max-age secure version
408 # For historical reasons, these attributes are also reserved:
409 # expires
411 # This is an extension from Microsoft:
412 # httponly
414 # This dictionary provides a mapping from the lowercase
415 # variant on the left to the appropriate traditional
416 # formatting on the right.
417 _reserved = { "expires" : "expires",
418 "path" : "Path",
419 "comment" : "Comment",
420 "domain" : "Domain",
421 "max-age" : "Max-Age",
422 "secure" : "secure",
423 "httponly" : "httponly",
424 "version" : "Version",
427 def __init__(self):
428 # Set defaults
429 self.key = self.value = self.coded_value = None
431 # Set default attributes
432 for K in self._reserved:
433 dict.__setitem__(self, K, "")
434 # end __init__
436 def __setitem__(self, K, V):
437 K = K.lower()
438 if not K in self._reserved:
439 raise CookieError("Invalid Attribute %s" % K)
440 dict.__setitem__(self, K, V)
441 # end __setitem__
443 def isReservedKey(self, K):
444 return K.lower() in self._reserved
445 # end isReservedKey
447 def set(self, key, val, coded_val,
448 LegalChars=_LegalChars,
449 idmap=_idmap, translate=string.translate):
450 # First we verify that the key isn't a reserved word
451 # Second we make sure it only contains legal characters
452 if key.lower() in self._reserved:
453 raise CookieError("Attempt to set a reserved key: %s" % key)
454 if "" != translate(key, idmap, LegalChars):
455 raise CookieError("Illegal key value: %s" % key)
457 # It's a good key, so save it.
458 self.key = key
459 self.value = val
460 self.coded_value = coded_val
461 # end set
463 def output(self, attrs=None, header = "Set-Cookie:"):
464 return "%s %s" % ( header, self.OutputString(attrs) )
466 __str__ = output
468 def __repr__(self):
469 return '<%s: %s=%s>' % (self.__class__.__name__,
470 self.key, repr(self.value) )
472 def js_output(self, attrs=None):
473 # Print javascript
474 return """
475 <script type="text/javascript">
476 <!-- begin hiding
477 document.cookie = \"%s\";
478 // end hiding -->
479 </script>
480 """ % ( self.OutputString(attrs), )
481 # end js_output()
483 def OutputString(self, attrs=None):
484 # Build up our result
486 result = []
487 RA = result.append
489 # First, the key=value pair
490 RA("%s=%s" % (self.key, self.coded_value))
492 # Now add any defined attributes
493 if attrs is None:
494 attrs = self._reserved
495 items = self.items()
496 items.sort()
497 for K,V in items:
498 if V == "": continue
499 if K not in attrs: continue
500 if K == "expires" and type(V) == type(1):
501 RA("%s=%s" % (self._reserved[K], _getdate(V)))
502 elif K == "max-age" and type(V) == type(1):
503 RA("%s=%d" % (self._reserved[K], V))
504 elif K == "secure":
505 RA(str(self._reserved[K]))
506 elif K == "httponly":
507 RA(str(self._reserved[K]))
508 else:
509 RA("%s=%s" % (self._reserved[K], V))
511 # Return the result
512 return _semispacejoin(result)
513 # end OutputString
514 # end Morsel class
519 # Pattern for finding cookie
521 # This used to be strict parsing based on the RFC2109 and RFC2068
522 # specifications. I have since discovered that MSIE 3.0x doesn't
523 # follow the character rules outlined in those specs. As a
524 # result, the parsing rules here are less strict.
527 _LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
528 _CookiePattern = re.compile(
529 r"(?x)" # This is a Verbose pattern
530 r"(?P<key>" # Start of group 'key'
531 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
532 r")" # End of group 'key'
533 r"\s*=\s*" # Equal Sign
534 r"(?P<val>" # Start of group 'val'
535 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
536 r"|" # or
537 ""+ _LegalCharsPatt +"*" # Any word or empty string
538 r")" # End of group 'val'
539 r"\s*;?" # Probably ending in a semi-colon
543 # At long last, here is the cookie class.
544 # Using this class is almost just like using a dictionary.
545 # See this module's docstring for example usage.
547 class BaseCookie(dict):
548 # A container class for a set of Morsels
551 def value_decode(self, val):
552 """real_value, coded_value = value_decode(STRING)
553 Called prior to setting a cookie's value from the network
554 representation. The VALUE is the value read from HTTP
555 header.
556 Override this function to modify the behavior of cookies.
558 return val, val
559 # end value_encode
561 def value_encode(self, val):
562 """real_value, coded_value = value_encode(VALUE)
563 Called prior to setting a cookie's value from the dictionary
564 representation. The VALUE is the value being assigned.
565 Override this function to modify the behavior of cookies.
567 strval = str(val)
568 return strval, strval
569 # end value_encode
571 def __init__(self, input=None):
572 if input: self.load(input)
573 # end __init__
575 def __set(self, key, real_value, coded_value):
576 """Private method for setting a cookie's value"""
577 M = self.get(key, Morsel())
578 M.set(key, real_value, coded_value)
579 dict.__setitem__(self, key, M)
580 # end __set
582 def __setitem__(self, key, value):
583 """Dictionary style assignment."""
584 rval, cval = self.value_encode(value)
585 self.__set(key, rval, cval)
586 # end __setitem__
588 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
589 """Return a string suitable for HTTP."""
590 result = []
591 items = self.items()
592 items.sort()
593 for K,V in items:
594 result.append( V.output(attrs, header) )
595 return sep.join(result)
596 # end output
598 __str__ = output
600 def __repr__(self):
601 L = []
602 items = self.items()
603 items.sort()
604 for K,V in items:
605 L.append( '%s=%s' % (K,repr(V.value) ) )
606 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
608 def js_output(self, attrs=None):
609 """Return a string suitable for JavaScript."""
610 result = []
611 items = self.items()
612 items.sort()
613 for K,V in items:
614 result.append( V.js_output(attrs) )
615 return _nulljoin(result)
616 # end js_output
618 def load(self, rawdata):
619 """Load cookies from a string (presumably HTTP_COOKIE) or
620 from a dictionary. Loading cookies from a dictionary 'd'
621 is equivalent to calling:
622 map(Cookie.__setitem__, d.keys(), d.values())
624 if type(rawdata) == type(""):
625 self.__ParseString(rawdata)
626 else:
627 self.update(rawdata)
628 return
629 # end load()
631 def __ParseString(self, str, patt=_CookiePattern):
632 i = 0 # Our starting point
633 n = len(str) # Length of string
634 M = None # current morsel
636 while 0 <= i < n:
637 # Start looking for a cookie
638 match = patt.search(str, i)
639 if not match: break # No more cookies
641 K,V = match.group("key"), match.group("val")
642 i = match.end(0)
644 # Parse the key, value in case it's metainfo
645 if K[0] == "$":
646 # We ignore attributes which pertain to the cookie
647 # mechanism as a whole. See RFC 2109.
648 # (Does anyone care?)
649 if M:
650 M[ K[1:] ] = V
651 elif K.lower() in Morsel._reserved:
652 if M:
653 M[ K ] = _unquote(V)
654 else:
655 rval, cval = self.value_decode(V)
656 self.__set(K, rval, cval)
657 M = self[K]
658 # end __ParseString
659 # end BaseCookie class
661 class SimpleCookie(BaseCookie):
662 """SimpleCookie
663 SimpleCookie supports strings as cookie values. When setting
664 the value using the dictionary assignment notation, SimpleCookie
665 calls the builtin str() to convert the value to a string. Values
666 received from HTTP are kept as strings.
668 def value_decode(self, val):
669 return _unquote( val ), val
670 def value_encode(self, val):
671 strval = str(val)
672 return strval, _quote( strval )
673 # end SimpleCookie
675 class SerialCookie(BaseCookie):
676 """SerialCookie
677 SerialCookie supports arbitrary objects as cookie values. All
678 values are serialized (using cPickle) before being sent to the
679 client. All incoming values are assumed to be valid Pickle
680 representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
681 FORMAT, THEN AN EXCEPTION WILL BE RAISED.
683 Note: Large cookie values add overhead because they must be
684 retransmitted on every HTTP transaction.
686 Note: HTTP has a 2k limit on the size of a cookie. This class
687 does not check for this limit, so be careful!!!
689 def __init__(self, input=None):
690 warnings.warn("SerialCookie class is insecure; do not use it",
691 DeprecationWarning)
692 BaseCookie.__init__(self, input)
693 # end __init__
694 def value_decode(self, val):
695 # This could raise an exception!
696 return loads( _unquote(val) ), val
697 def value_encode(self, val):
698 return val, _quote( dumps(val) )
699 # end SerialCookie
701 class SmartCookie(BaseCookie):
702 """SmartCookie
703 SmartCookie supports arbitrary objects as cookie values. If the
704 object is a string, then it is quoted. If the object is not a
705 string, however, then SmartCookie will use cPickle to serialize
706 the object into a string representation.
708 Note: Large cookie values add overhead because they must be
709 retransmitted on every HTTP transaction.
711 Note: HTTP has a 2k limit on the size of a cookie. This class
712 does not check for this limit, so be careful!!!
714 def __init__(self, input=None):
715 warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
716 DeprecationWarning)
717 BaseCookie.__init__(self, input)
718 # end __init__
719 def value_decode(self, val):
720 strval = _unquote(val)
721 try:
722 return loads(strval), val
723 except:
724 return strval, val
725 def value_encode(self, val):
726 if type(val) == type(""):
727 return val, _quote(val)
728 else:
729 return val, _quote( dumps(val) )
730 # end SmartCookie
733 ###########################################################
734 # Backwards Compatibility: Don't break any existing code!
736 # We provide Cookie() as an alias for SmartCookie()
737 Cookie = SmartCookie
740 ###########################################################
742 def _test():
743 import doctest, Cookie
744 return doctest.testmod(Cookie)
746 if __name__ == "__main__":
747 _test()
750 #Local Variables:
751 #tab-width: 4
752 #end: