Bump version to 1.0.
[python/dscho.git] / Lib / dos-8x3 / cookie.py
blob67259af5f6945fc30077818593e4eb07999b9d6c
1 #!/usr/bin/env python
4 ####
5 # Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
6 #
7 # All Rights Reserved
8 #
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 """
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: sugar=wafer;
74 Set-Cookie: fig=newton;
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: vienna=finger;
97 Set-Cookie: chips=ahoy;
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 >>> C.__class__
207 <class Cookie.SmartCookie at 99f88>
210 Finis.
211 """ #"
213 # |----helps out font-lock
216 # Import our required modules
218 import string, sys
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"
233 # Define an exception visible to External modules
235 class CookieError(Exception):
236 pass
239 # These quoting routines conform to the RFC2109 specification, which in
240 # turn references the character definitions from RFC2068. They provide
241 # a two-way quoting algorithm. Any non-text character is translated
242 # into a 4 character sequence: a forward-slash followed by the
243 # three-digit octal equivalent of the character. Any '\' or '"' is
244 # quoted with a preceeding '\' slash.
246 # These are taken from RFC2068 and RFC2109.
247 # _LegalChars is the list of chars which don't require "'s
248 # _Translator hash-table for fast quoting
250 _LegalChars = string.letters + string.digits + "!#$%&'*+-.^_`|~"
251 _Translator = {
252 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
253 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
254 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
255 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
256 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
257 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
258 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
259 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
260 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
261 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
262 '\036' : '\\036', '\037' : '\\037',
264 '"' : '\\"', '\\' : '\\\\',
266 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
267 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
268 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
269 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
270 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
271 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
272 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
273 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
274 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
275 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
276 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
277 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
278 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
279 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
280 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
281 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
282 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
283 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
284 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
285 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
286 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
287 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
288 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
289 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
290 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
291 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
292 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
293 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
294 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
295 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
296 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
297 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
298 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
299 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
300 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
301 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
302 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
303 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
304 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
305 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
306 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
307 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
308 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
311 def _quote(str, LegalChars=_LegalChars,
312 join=string.join, idmap=string._idmap, translate=string.translate):
314 # If the string does not need to be double-quoted,
315 # then just return the string. Otherwise, surround
316 # the string in doublequotes and precede quote (with a \)
317 # special characters.
319 if "" == translate(str, idmap, LegalChars):
320 return str
321 else:
322 return '"' + join( map(_Translator.get, str, str), "" ) + '"'
323 # end _quote
326 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
327 _QuotePatt = re.compile(r"[\\].")
329 def _unquote(str, join=string.join, atoi=string.atoi):
330 # If there aren't any doublequotes,
331 # then there can't be any special characters. See RFC 2109.
332 if len(str) < 2:
333 return str
334 if str[0] != '"' or str[-1] != '"':
335 return str
337 # We have to assume that we must decode this string.
338 # Down to work.
340 # Remove the "s
341 str = str[1:-1]
343 # Check for special sequences. Examples:
344 # \012 --> \n
345 # \" --> "
347 i = 0
348 n = len(str)
349 res = []
350 while 0 <= i < n:
351 Omatch = _OctalPatt.search(str, i)
352 Qmatch = _QuotePatt.search(str, i)
353 if not Omatch and not Qmatch: # Neither matched
354 res.append(str[i:])
355 break
356 # else:
357 j = k = -1
358 if Omatch: j = Omatch.start(0)
359 if Qmatch: k = Qmatch.start(0)
360 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
361 res.append(str[i:k])
362 res.append(str[k+1])
363 i = k+2
364 else: # OctalPatt matched
365 res.append(str[i:j])
366 res.append( chr( atoi(str[j+1:j+4], 8) ) )
367 i = j+4
368 return join(res, "")
369 # end _unquote
371 # The _getdate() routine is used to set the expiration time in
372 # the cookie's HTTP header. By default, _getdate() returns the
373 # current time in the appropriate "expires" format for a
374 # Set-Cookie header. The one optional argument is an offset from
375 # now, in seconds. For example, an offset of -3600 means "one hour ago".
376 # The offset may be a floating point number.
379 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
381 _monthname = [None,
382 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
383 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
385 def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
386 from time import gmtime, time
387 now = time()
388 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
389 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
390 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
394 # A class to hold ONE key,value pair.
395 # In a cookie, each such pair may have several attributes.
396 # so this class is used to keep the attributes associated
397 # with the appropriate key,value pair.
398 # This class also includes a coded_value attribute, which
399 # is used to hold the network representation of the
400 # value. This is most useful when Python objects are
401 # pickled for network transit.
404 class Morsel(UserDict):
405 # RFC 2109 lists these attributes as reserved:
406 # path comment domain
407 # max-age secure version
409 # For historical reasons, these attributes are also reserved:
410 # expires
412 # This dictionary provides a mapping from the lowercase
413 # variant on the left to the appropriate traditional
414 # formatting on the right.
415 _reserved = { "expires" : "expires",
416 "path" : "Path",
417 "comment" : "Comment",
418 "domain" : "Domain",
419 "max-age" : "Max-Age",
420 "secure" : "secure",
421 "version" : "Version",
423 _reserved_keys = _reserved.keys()
425 def __init__(self):
426 # Set defaults
427 self.key = self.value = self.coded_value = None
428 UserDict.__init__(self)
430 # Set default attributes
431 for K in self._reserved_keys:
432 UserDict.__setitem__(self, K, "")
433 # end __init__
435 def __setitem__(self, K, V):
436 K = string.lower(K)
437 if not K in self._reserved_keys:
438 raise CookieError("Invalid Attribute %s" % K)
439 UserDict.__setitem__(self, K, V)
440 # end __setitem__
442 def isReservedKey(self, K):
443 return string.lower(K) in self._reserved_keys
444 # end isReservedKey
446 def set(self, key, val, coded_val,
447 LegalChars=_LegalChars,
448 idmap=string._idmap, translate=string.translate ):
449 # First we verify that the key isn't a reserved word
450 # Second we make sure it only contains legal characters
451 if string.lower(key) in self._reserved_keys:
452 raise CookieError("Attempt to set a reserved key: %s" % key)
453 if "" != translate(key, idmap, LegalChars):
454 raise CookieError("Illegal key value: %s" % key)
456 # It's a good key, so save it.
457 self.key = key
458 self.value = val
459 self.coded_value = coded_val
460 # end set
462 def output(self, attrs=None, header = "Set-Cookie:"):
463 return "%s %s" % ( header, self.OutputString(attrs) )
465 __str__ = output
467 def __repr__(self):
468 return '<%s: %s=%s>' % (self.__class__.__name__,
469 self.key, repr(self.value) )
471 def js_output(self, attrs=None):
472 # Print javascript
473 return """
474 <SCRIPT LANGUAGE="JavaScript">
475 <!-- begin hiding
476 document.cookie = \"%s\"
477 // end hiding -->
478 </script>
479 """ % ( self.OutputString(attrs), )
480 # end js_output()
482 def OutputString(self, attrs=None):
483 # Build up our result
485 result = []
486 RA = result.append
488 # First, the key=value pair
489 RA("%s=%s;" % (self.key, self.coded_value))
491 # Now add any defined attributes
492 if attrs == None:
493 attrs = self._reserved_keys
494 for K,V in self.items():
495 if V == "": continue
496 if K not in attrs: continue
497 if K == "expires" and type(V) == type(1):
498 RA("%s=%s;" % (self._reserved[K], _getdate(V)))
499 elif K == "max-age" and type(V) == type(1):
500 RA("%s=%d;" % (self._reserved[K], V))
501 elif K == "secure":
502 RA("%s;" % self._reserved[K])
503 else:
504 RA("%s=%s;" % (self._reserved[K], V))
506 # Return the result
507 return string.join(result, " ")
508 # end OutputString
509 # end Morsel class
514 # Pattern for finding cookie
516 # This used to be strict parsing based on the RFC2109 and RFC2068
517 # specifications. I have since discovered that MSIE 3.0x doesn't
518 # follow the character rules outlined in those specs. As a
519 # result, the parsing rules here are less strict.
522 _LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{]"
523 _CookiePattern = re.compile(
524 r"(?x)" # This is a Verbose pattern
525 r"(?P<key>" # Start of group 'key'
526 ""+ _LegalCharsPatt +"+" # Any word of at least one letter
527 r")" # End of group 'key'
528 r"\s*=\s*" # Equal Sign
529 r"(?P<val>" # Start of group 'val'
530 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
531 r"|" # or
532 ""+ _LegalCharsPatt +"*" # Any word or empty string
533 r")" # End of group 'val'
534 r"\s*;?" # Probably ending in a semi-colon
538 # At long last, here is the cookie class.
539 # Using this class is almost just like using a dictionary.
540 # See this module's docstring for example usage.
542 class BaseCookie(UserDict):
543 # A container class for a set of Morsels
546 def value_decode(self, val):
547 """real_value, coded_value = value_decode(STRING)
548 Called prior to setting a cookie's value from the network
549 representation. The VALUE is the value read from HTTP
550 header.
551 Override this function to modify the behavior of cookies.
553 return val, val
554 # end value_encode
556 def value_encode(self, val):
557 """real_value, coded_value = value_encode(VALUE)
558 Called prior to setting a cookie's value from the dictionary
559 representation. The VALUE is the value being assigned.
560 Override this function to modify the behavior of cookies.
562 strval = str(val)
563 return strval, strval
564 # end value_encode
566 def __init__(self, input=None):
567 UserDict.__init__(self)
568 if input: self.load(input)
569 # end __init__
571 def __set(self, key, real_value, coded_value):
572 """Private method for setting a cookie's value"""
573 M = self.get(key, Morsel())
574 M.set(key, real_value, coded_value)
575 UserDict.__setitem__(self, key, M)
576 # end __set
578 def __setitem__(self, key, value):
579 """Dictionary style assignment."""
580 rval, cval = self.value_encode(value)
581 self.__set(key, rval, cval)
582 # end __setitem__
584 def output(self, attrs=None, header="Set-Cookie:", sep="\n"):
585 """Return a string suitable for HTTP."""
586 result = []
587 for K,V in self.items():
588 result.append( V.output(attrs, header) )
589 return string.join(result, sep)
590 # end output
592 __str__ = output
594 def __repr__(self):
595 L = []
596 for K,V in self.items():
597 L.append( '%s=%s' % (K,repr(V.value) ) )
598 return '<%s: %s>' % (self.__class__.__name__, string.join(L))
600 def js_output(self, attrs=None):
601 """Return a string suitable for JavaScript."""
602 result = []
603 for K,V in self.items():
604 result.append( V.js_output(attrs) )
605 return string.join(result, "")
606 # end js_output
608 def load(self, rawdata):
609 """Load cookies from a string (presumably HTTP_COOKIE) or
610 from a dictionary. Loading cookies from a dictionary 'd'
611 is equivalent to calling:
612 map(Cookie.__setitem__, d.keys(), d.values())
614 if type(rawdata) == type(""):
615 self.__ParseString(rawdata)
616 else:
617 self.update(rawdata)
618 return
619 # end load()
621 def __ParseString(self, str, patt=_CookiePattern):
622 i = 0 # Our starting point
623 n = len(str) # Length of string
624 M = None # current morsel
626 while 0 <= i < n:
627 # Start looking for a cookie
628 match = patt.search(str, i)
629 if not match: break # No more cookies
631 K,V = match.group("key"), match.group("val")
632 i = match.end(0)
634 # Parse the key, value in case it's metainfo
635 if K[0] == "$":
636 # We ignore attributes which pertain to the cookie
637 # mechanism as a whole. See RFC 2109.
638 # (Does anyone care?)
639 if M:
640 M[ K[1:] ] = V
641 elif string.lower(K) in Morsel._reserved_keys:
642 if M:
643 M[ K ] = _unquote(V)
644 else:
645 rval, cval = self.value_decode(V)
646 self.__set(K, rval, cval)
647 M = self[K]
648 # end __ParseString
649 # end BaseCookie class
651 class SimpleCookie(BaseCookie):
652 """SimpleCookie
653 SimpleCookie supports strings as cookie values. When setting
654 the value using the dictionary assignment notation, SimpleCookie
655 calls the builtin str() to convert the value to a string. Values
656 received from HTTP are kept as strings.
658 def value_decode(self, val):
659 return _unquote( val ), val
660 def value_encode(self, val):
661 strval = str(val)
662 return strval, _quote( strval )
663 # end SimpleCookie
665 class SerialCookie(BaseCookie):
666 """SerialCookie
667 SerialCookie supports arbitrary objects as cookie values. All
668 values are serialized (using cPickle) before being sent to the
669 client. All incoming values are assumed to be valid Pickle
670 representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
671 FORMAT, THEN AN EXCEPTION WILL BE RAISED.
673 Note: Large cookie values add overhead because they must be
674 retransmitted on every HTTP transaction.
676 Note: HTTP has a 2k limit on the size of a cookie. This class
677 does not check for this limit, so be careful!!!
679 def value_decode(self, val):
680 # This could raise an exception!
681 return loads( _unquote(val) ), val
682 def value_encode(self, val):
683 return val, _quote( dumps(val) )
684 # end SerialCookie
686 class SmartCookie(BaseCookie):
687 """SmartCookie
688 SmartCookie supports arbitrary objects as cookie values. If the
689 object is a string, then it is quoted. If the object is not a
690 string, however, then SmartCookie will use cPickle to serialize
691 the object into a string representation.
693 Note: Large cookie values add overhead because they must be
694 retransmitted on every HTTP transaction.
696 Note: HTTP has a 2k limit on the size of a cookie. This class
697 does not check for this limit, so be careful!!!
699 def value_decode(self, val):
700 strval = _unquote(val)
701 try:
702 return loads(strval), val
703 except:
704 return strval, val
705 def value_encode(self, val):
706 if type(val) == type(""):
707 return val, _quote(val)
708 else:
709 return val, _quote( dumps(val) )
710 # end SmartCookie
713 ###########################################################
714 # Backwards Compatibility: Don't break any existing code!
716 # We provide Cookie() as an alias for SmartCookie()
717 Cookie = SmartCookie
720 ###########################################################
724 #Local Variables:
725 #tab-width: 4
726 #end: