This commit was manufactured by cvs2svn to create tag
[python/dscho.git] / Lib / Cookie.py
blob8e596571ada579571dac61949ec6e096c2ec88dd
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 slighly different encoding semanitcs, 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 >>> print C
73 Set-Cookie: fig=newton;
74 Set-Cookie: sugar=wafer;
76 Notice that the printable representation of a Cookie is the
77 appropriate format for a Set-Cookie: header. This is the
78 default behavior. You can change the header and printed
79 attributes by using the the .output() function
81 >>> C = Cookie.SmartCookie()
82 >>> C["rocky"] = "road"
83 >>> C["rocky"]["path"] = "/cookie"
84 >>> print C.output(header="Cookie:")
85 Cookie: rocky=road; Path=/cookie;
86 >>> print C.output(attrs=[], header="Cookie:")
87 Cookie: rocky=road;
89 The load() method of a Cookie extracts cookies from a string. In a
90 CGI script, you would use this method to extract the cookies from the
91 HTTP_COOKIE environment variable.
93 >>> C = Cookie.SmartCookie()
94 >>> C.load("chips=ahoy; vienna=finger")
95 >>> print C
96 Set-Cookie: chips=ahoy;
97 Set-Cookie: vienna=finger;
99 The load() method is darn-tootin smart about identifying cookies
100 within a string. Escaped quotation marks, nested semicolons, and other
101 such trickeries do not confuse it.
103 >>> C = Cookie.SmartCookie()
104 >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
105 >>> print C
106 Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;";
108 Each element of the Cookie also supports all of the RFC 2109
109 Cookie attributes. Here's an example which sets the Path
110 attribute.
112 >>> C = Cookie.SmartCookie()
113 >>> C["oreo"] = "doublestuff"
114 >>> C["oreo"]["path"] = "/"
115 >>> print C
116 Set-Cookie: oreo=doublestuff; Path=/;
118 Each dictionary element has a 'value' attribute, which gives you
119 back the value associated with the key.
121 >>> C = Cookie.SmartCookie()
122 >>> C["twix"] = "none for you"
123 >>> C["twix"].value
124 'none for you'
127 A Bit More Advanced
128 -------------------
130 As mentioned before, there are three different flavors of Cookie
131 objects, each with different encoding/decoding semantics. This
132 section briefly discusses the differences.
134 SimpleCookie
136 The SimpleCookie expects that all values should be standard strings.
137 Just to be sure, SimpleCookie invokes the str() builtin to convert
138 the value to a string, when the values are set dictionary-style.
140 >>> C = Cookie.SimpleCookie()
141 >>> C["number"] = 7
142 >>> C["string"] = "seven"
143 >>> C["number"].value
145 >>> C["string"].value
146 'seven'
147 >>> print C
148 Set-Cookie: number=7;
149 Set-Cookie: string=seven;
152 SerialCookie
154 The SerialCookie expects that all values should be serialized using
155 cPickle (or pickle, if cPickle isn't available). As a result of
156 serializing, SerialCookie can save almost any Python object to a
157 value, and recover the exact same object when the cookie has been
158 returned. (SerialCookie can yield some strange-looking cookie
159 values, however.)
161 >>> C = Cookie.SerialCookie()
162 >>> C["number"] = 7
163 >>> C["string"] = "seven"
164 >>> C["number"].value
166 >>> C["string"].value
167 'seven'
168 >>> print C
169 Set-Cookie: number="I7\012.";
170 Set-Cookie: string="S'seven'\012p1\012.";
172 Be warned, however, if SerialCookie cannot de-serialize a value (because
173 it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
176 SmartCookie
178 The SmartCookie combines aspects of each of the other two flavors.
179 When setting a value in a dictionary-fashion, the SmartCookie will
180 serialize (ala cPickle) the value *if and only if* it isn't a
181 Python string. String objects are *not* serialized. Similarly,
182 when the load() method parses out values, it attempts to de-serialize
183 the value. If it fails, then it fallsback to treating the value
184 as a string.
186 >>> C = Cookie.SmartCookie()
187 >>> C["number"] = 7
188 >>> C["string"] = "seven"
189 >>> C["number"].value
191 >>> C["string"].value
192 'seven'
193 >>> print C
194 Set-Cookie: number="I7\012.";
195 Set-Cookie: string=seven;
198 Backwards Compatibility
199 -----------------------
201 In order to keep compatibilty with earlier versions of Cookie.py,
202 it is still possible to use Cookie.Cookie() to create a Cookie. In
203 fact, this simply returns a SmartCookie.
205 >>> C = Cookie.Cookie()
206 >>> print C.__class__.__name__
207 SmartCookie
210 Finis.
211 """ #"
213 # |----helps out font-lock
216 # Import our required modules
218 import string
219 from UserDict import UserDict
221 try:
222 from cPickle import dumps, loads
223 except ImportError:
224 from pickle import dumps, loads
226 try:
227 import re
228 except ImportError:
229 raise ImportError, "Cookie.py requires 're' from Python 1.5 or later"
231 __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
232 "SmartCookie","Cookie"]
235 # Define an exception visible to External modules
237 class CookieError(Exception):
238 pass
241 # These quoting routines conform to the RFC2109 specification, which in
242 # turn references the character definitions from RFC2068. They provide
243 # a two-way quoting algorithm. Any non-text character is translated
244 # into a 4 character sequence: a forward-slash followed by the
245 # three-digit octal equivalent of the character. Any '\' or '"' is
246 # quoted with a preceeding '\' slash.
248 # These are taken from RFC2068 and RFC2109.
249 # _LegalChars is the list of chars which don't require "'s
250 # _Translator hash-table for fast quoting
252 _LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
253 _Translator = {
254 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
255 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
256 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
257 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
258 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
259 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
260 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
261 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
262 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
263 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
264 '\036' : '\\036', '\037' : '\\037',
266 '"' : '\\"', '\\' : '\\\\',
268 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
269 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
270 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
271 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
272 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
273 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
274 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
275 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
276 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
277 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
278 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
279 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
280 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
281 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
282 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
283 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
284 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
285 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
286 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
287 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
288 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
289 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
290 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
291 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
292 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
293 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
294 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
295 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
296 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
297 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
298 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
299 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
300 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
301 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
302 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
303 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
304 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
305 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
306 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
307 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
308 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
309 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
310 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
313 def _quote(str, LegalChars=_LegalChars,
314 join=string.join, idmap=string._idmap, translate=string.translate):
316 # If the string does not need to be double-quoted,
317 # then just return the string. Otherwise, surround
318 # the string in doublequotes and precede quote (with a \)
319 # special characters.
321 if "" == translate(str, idmap, LegalChars):
322 return str
323 else:
324 return '"' + join( map(_Translator.get, str, str), "" ) + '"'
325 # end _quote
328 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
329 _QuotePatt = re.compile(r"[\\].")
331 def _unquote(str, join=string.join, atoi=string.atoi):
332 # If there aren't any doublequotes,
333 # then there can't be any special characters. See RFC 2109.
334 if len(str) < 2:
335 return str
336 if str[0] != '"' or str[-1] != '"':
337 return str
339 # We have to assume that we must decode this string.
340 # Down to work.
342 # Remove the "s
343 str = str[1:-1]
345 # Check for special sequences. Examples:
346 # \012 --> \n
347 # \" --> "
349 i = 0
350 n = len(str)
351 res = []
352 while 0 <= i < n:
353 Omatch = _OctalPatt.search(str, i)
354 Qmatch = _QuotePatt.search(str, i)
355 if not Omatch and not Qmatch: # Neither matched
356 res.append(str[i:])
357 break
358 # else:
359 j = k = -1
360 if Omatch: j = Omatch.start(0)
361 if Qmatch: k = Qmatch.start(0)
362 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
363 res.append(str[i:k])
364 res.append(str[k+1])
365 i = k+2
366 else: # OctalPatt matched
367 res.append(str[i:j])
368 res.append( chr( atoi(str[j+1:j+4], 8) ) )
369 i = j+4
370 return join(res, "")
371 # end _unquote
373 # The _getdate() routine is used to set the expiration time in
374 # the cookie's HTTP header. By default, _getdate() returns the
375 # current time in the appropriate "expires" format for a
376 # Set-Cookie header. The one optional argument is an offset from
377 # now, in seconds. For example, an offset of -3600 means "one hour ago".
378 # The offset may be a floating point number.
381 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
383 _monthname = [None,
384 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
385 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
387 def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
388 from time import gmtime, time
389 now = time()
390 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
391 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
392 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
396 # A class to hold ONE key,value pair.
397 # In a cookie, each such pair may have several attributes.
398 # so this class is used to keep the attributes associated
399 # with the appropriate key,value pair.
400 # This class also includes a coded_value attribute, which
401 # is used to hold the network representation of the
402 # value. This is most useful when Python objects are
403 # pickled for network transit.
406 class Morsel(UserDict):
407 # RFC 2109 lists these attributes as reserved:
408 # path comment domain
409 # max-age secure version
411 # For historical reasons, these attributes are also reserved:
412 # expires
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 "version" : "Version",
425 _reserved_keys = _reserved.keys()
427 def __init__(self):
428 # Set defaults
429 self.key = self.value = self.coded_value = None
430 UserDict.__init__(self)
432 # Set default attributes
433 for K in self._reserved_keys:
434 UserDict.__setitem__(self, K, "")
435 # end __init__
437 def __setitem__(self, K, V):
438 K = string.lower(K)
439 if not K in self._reserved_keys:
440 raise CookieError("Invalid Attribute %s" % K)
441 UserDict.__setitem__(self, K, V)
442 # end __setitem__
444 def isReservedKey(self, K):
445 return string.lower(K) in self._reserved_keys
446 # end isReservedKey
448 def set(self, key, val, coded_val,
449 LegalChars=_LegalChars,
450 idmap=string._idmap, translate=string.translate ):
451 # First we verify that the key isn't a reserved word
452 # Second we make sure it only contains legal characters
453 if string.lower(key) in self._reserved_keys:
454 raise CookieError("Attempt to set a reserved key: %s" % key)
455 if "" != translate(key, idmap, LegalChars):
456 raise CookieError("Illegal key value: %s" % key)
458 # It's a good key, so save it.
459 self.key = key
460 self.value = val
461 self.coded_value = coded_val
462 # end set
464 def output(self, attrs=None, header = "Set-Cookie:"):
465 return "%s %s" % ( header, self.OutputString(attrs) )
467 __str__ = output
469 def __repr__(self):
470 return '<%s: %s=%s>' % (self.__class__.__name__,
471 self.key, repr(self.value) )
473 def js_output(self, attrs=None):
474 # Print javascript
475 return """
476 <SCRIPT LANGUAGE="JavaScript">
477 <!-- begin hiding
478 document.cookie = \"%s\"
479 // end hiding -->
480 </script>
481 """ % ( self.OutputString(attrs), )
482 # end js_output()
484 def OutputString(self, attrs=None):
485 # Build up our result
487 result = []
488 RA = result.append
490 # First, the key=value pair
491 RA("%s=%s;" % (self.key, self.coded_value))
493 # Now add any defined attributes
494 if attrs is None:
495 attrs = self._reserved_keys
496 items = self.items()
497 items.sort()
498 for K,V in items:
499 if V == "": continue
500 if K not in attrs: continue
501 if K == "expires" and type(V) == type(1):
502 RA("%s=%s;" % (self._reserved[K], _getdate(V)))
503 elif K == "max-age" and type(V) == type(1):
504 RA("%s=%d;" % (self._reserved[K], V))
505 elif K == "secure":
506 RA("%s;" % self._reserved[K])
507 else:
508 RA("%s=%s;" % (self._reserved[K], V))
510 # Return the result
511 return string.join(result, " ")
512 # end OutputString
513 # end Morsel class
518 # Pattern for finding cookie
520 # This used to be strict parsing based on the RFC2109 and RFC2068
521 # specifications. I have since discovered that MSIE 3.0x doesn't
522 # follow the character rules outlined in those specs. As a
523 # result, the parsing rules here are less strict.
526 _LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
527 _CookiePattern = re.compile(
528 r"(?x)" # This is a Verbose pattern
529 r"(?P<key>" # Start of group 'key'
530 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
531 r")" # End of group 'key'
532 r"\s*=\s*" # Equal Sign
533 r"(?P<val>" # Start of group 'val'
534 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
535 r"|" # or
536 ""+ _LegalCharsPatt +"*" # Any word or empty string
537 r")" # End of group 'val'
538 r"\s*;?" # Probably ending in a semi-colon
542 # At long last, here is the cookie class.
543 # Using this class is almost just like using a dictionary.
544 # See this module's docstring for example usage.
546 class BaseCookie(UserDict):
547 # A container class for a set of Morsels
550 def value_decode(self, val):
551 """real_value, coded_value = value_decode(STRING)
552 Called prior to setting a cookie's value from the network
553 representation. The VALUE is the value read from HTTP
554 header.
555 Override this function to modify the behavior of cookies.
557 return val, val
558 # end value_encode
560 def value_encode(self, val):
561 """real_value, coded_value = value_encode(VALUE)
562 Called prior to setting a cookie's value from the dictionary
563 representation. The VALUE is the value being assigned.
564 Override this function to modify the behavior of cookies.
566 strval = str(val)
567 return strval, strval
568 # end value_encode
570 def __init__(self, input=None):
571 UserDict.__init__(self)
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 UserDict.__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="\n"):
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 string.join(result, sep)
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__, string.join(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 string.join(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 string.lower(K) in Morsel._reserved_keys:
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 value_decode(self, val):
690 # This could raise an exception!
691 return loads( _unquote(val) ), val
692 def value_encode(self, val):
693 return val, _quote( dumps(val) )
694 # end SerialCookie
696 class SmartCookie(BaseCookie):
697 """SmartCookie
698 SmartCookie supports arbitrary objects as cookie values. If the
699 object is a string, then it is quoted. If the object is not a
700 string, however, then SmartCookie will use cPickle to serialize
701 the object into a string representation.
703 Note: Large cookie values add overhead because they must be
704 retransmitted on every HTTP transaction.
706 Note: HTTP has a 2k limit on the size of a cookie. This class
707 does not check for this limit, so be careful!!!
709 def value_decode(self, val):
710 strval = _unquote(val)
711 try:
712 return loads(strval), val
713 except:
714 return strval, val
715 def value_encode(self, val):
716 if type(val) == type(""):
717 return val, _quote(val)
718 else:
719 return val, _quote( dumps(val) )
720 # end SmartCookie
723 ###########################################################
724 # Backwards Compatibility: Don't break any existing code!
726 # We provide Cookie() as an alias for SmartCookie()
727 Cookie = SmartCookie
730 ###########################################################
732 def _test():
733 import doctest, Cookie
734 return doctest.testmod(Cookie)
736 if __name__ == "__main__":
737 _test()
740 #Local Variables:
741 #tab-width: 4
742 #end: