Vega strike Python Modules doc  0.5.1
Documentation of the " Modules " folder of Vega strike
 All Data Structures Namespaces Files Functions Variables
Cookie.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 
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.
17 #
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.
26 #
27 ####
28 #
29 # Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
30 # by Timothy O'Malley <timo@alum.mit.edu>
31 #
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.
35 #
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.
39 #
40 ####
41 
42 r"""
43 Here's a sample session to show how to use this module.
44 At the moment, this is the only documentation.
45 
46 The Basics
47 ----------
48 
49 Importing is easy..
50 
51  >>> import Cookie
52 
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.
56 
57  >>> C = Cookie.SimpleCookie()
58  >>> C = Cookie.SerialCookie()
59  >>> C = Cookie.SmartCookie()
60 
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.]
65 
66 Once you've created your Cookie, you can add values just as if it were
67 a dictionary.
68 
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;
75 
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
80 
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;
88 
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.
92 
93  >>> C = Cookie.SmartCookie()
94  >>> C.load("chips=ahoy; vienna=finger")
95  >>> print C
96  Set-Cookie: chips=ahoy;
97  Set-Cookie: vienna=finger;
98 
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.
102 
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;";
107 
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.
111 
112  >>> C = Cookie.SmartCookie()
113  >>> C["oreo"] = "doublestuff"
114  >>> C["oreo"]["path"] = "/"
115  >>> print C
116  Set-Cookie: oreo=doublestuff; Path=/;
117 
118 Each dictionary element has a 'value' attribute, which gives you
119 back the value associated with the key.
120 
121  >>> C = Cookie.SmartCookie()
122  >>> C["twix"] = "none for you"
123  >>> C["twix"].value
124  'none for you'
125 
126 
127 A Bit More Advanced
128 -------------------
129 
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.
133 
134 SimpleCookie
135 
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.
139 
140  >>> C = Cookie.SimpleCookie()
141  >>> C["number"] = 7
142  >>> C["string"] = "seven"
143  >>> C["number"].value
144  '7'
145  >>> C["string"].value
146  'seven'
147  >>> print C
148  Set-Cookie: number=7;
149  Set-Cookie: string=seven;
150 
151 
152 SerialCookie
153 
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.)
160 
161  >>> C = Cookie.SerialCookie()
162  >>> C["number"] = 7
163  >>> C["string"] = "seven"
164  >>> C["number"].value
165  7
166  >>> C["string"].value
167  'seven'
168  >>> print C
169  Set-Cookie: number="I7\012.";
170  Set-Cookie: string="S'seven'\012p1\012.";
171 
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.
174 
175 
176 SmartCookie
177 
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.
185 
186  >>> C = Cookie.SmartCookie()
187  >>> C["number"] = 7
188  >>> C["string"] = "seven"
189  >>> C["number"].value
190  7
191  >>> C["string"].value
192  'seven'
193  >>> print C
194  Set-Cookie: number="I7\012.";
195  Set-Cookie: string=seven;
196 
197 
198 Backwards Compatibility
199 -----------------------
200 
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.
204 
205  >>> C = Cookie.Cookie()
206  >>> print C.__class__.__name__
207  SmartCookie
208 
209 
210 Finis.
211 """ #"
212 # ^
213 # |----helps out font-lock
214 
215 #
216 # Import our required modules
217 #
218 import string
219 from UserDict import UserDict
220 
221 try:
222  from cPickle import dumps, loads
223 except ImportError:
224  from pickle import dumps, loads
225 
226 try:
227  import re
228 except ImportError:
229  raise ImportError, "Cookie.py requires 're' from Python 1.5 or later"
230 
231 __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
232  "SmartCookie","Cookie"]
233 
234 #
235 # Define an exception visible to External modules
236 #
237 class CookieError(Exception):
238  pass
239 
240 
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.
247 #
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
251 #
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',
265 
266  '"' : '\\"', '\\' : '\\\\',
267 
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'
311  }
312 
313 def _quote(str, LegalChars=_LegalChars,
314  join=string.join, idmap=string._idmap, translate=string.translate):
315  #
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.
320  #
321  if "" == translate(str, idmap, LegalChars):
322  return str
323  else:
324  return '"' + join( map(_Translator.get, str, str), "" ) + '"'
325 # end _quote
326 
327 
328 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
329 _QuotePatt = re.compile(r"[\\].")
330 
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
338 
339  # We have to assume that we must decode this string.
340  # Down to work.
341 
342  # Remove the "s
343  str = str[1:-1]
344 
345  # Check for special sequences. Examples:
346  # \012 --> \n
347  # \" --> "
348  #
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
372 
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.
379 #
380 
381 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
382 
383 _monthname = [None,
384  'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
385  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
386 
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)
393 
394 
395 #
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.
404 #
405 
407  # RFC 2109 lists these attributes as reserved:
408  # path comment domain
409  # max-age secure version
410  #
411  # For historical reasons, these attributes are also reserved:
412  # expires
413  #
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",
424  }
425  _reserved_keys = _reserved.keys()
426 
427  def __init__(self):
428  # Set defaults
429  self.key = self.value = self.coded_value = None
430  UserDict.__init__(self)
431 
432  # Set default attributes
433  for K in self._reserved_keys:
434  UserDict.__setitem__(self, K, "")
435  # end __init__
436 
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__
443 
444  def isReservedKey(self, K):
445  return string.lower(K) in self._reserved_keys
446  # end isReservedKey
447 
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)
457 
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
463 
464  def output(self, attrs=None, header = "Set-Cookie:"):
465  return "%s %s" % ( header, self.OutputString(attrs) )
466 
467  __str__ = output
468 
469  def __repr__(self):
470  return '<%s: %s=%s>' % (self.__class__.__name__,
471  self.key, repr(self.value) )
472 
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()
483 
484  def OutputString(self, attrs=None):
485  # Build up our result
486  #
487  result = []
488  RA = result.append
489 
490  # First, the key=value pair
491  RA("%s=%s;" % (self.key, self.coded_value))
492 
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))
509 
510  # Return the result
511  return string.join(result, " ")
512  # end OutputString
513 # end Morsel class
514 
515 
516 
517 #
518 # Pattern for finding cookie
519 #
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.
524 #
525 
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
539  )
540 
541 
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.
545 #
546 class BaseCookie(UserDict):
547  # A container class for a set of Morsels
548  #
549 
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.
556  """
557  return val, val
558  # end value_encode
559 
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.
565  """
566  strval = str(val)
567  return strval, strval
568  # end value_encode
569 
570  def __init__(self, input=None):
571  UserDict.__init__(self)
572  if input: self.load(input)
573  # end __init__
574 
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
581 
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__
587 
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
597 
598  __str__ = output
599 
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))
607 
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
617 
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())
623  """
624  if type(rawdata) == type(""):
625  self.__ParseString(rawdata)
626  else:
627  self.update(rawdata)
628  return
629  # end load()
630 
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
635 
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
640 
641  K,V = match.group("key"), match.group("val")
642  i = match.end(0)
643 
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
660 
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.
667  """
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
674 
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.
682 
683  Note: Large cookie values add overhead because they must be
684  retransmitted on every HTTP transaction.
685 
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!!!
688  """
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
695 
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.
702 
703  Note: Large cookie values add overhead because they must be
704  retransmitted on every HTTP transaction.
705 
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!!!
708  """
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
721 
722 
723 ###########################################################
724 # Backwards Compatibility: Don't break any existing code!
725 
726 # We provide Cookie() as an alias for SmartCookie()
727 Cookie = SmartCookie
728 
729 #
730 ###########################################################
731 
732 def _test():
733  import doctest, Cookie
734  return doctest.testmod(Cookie)
735 
736 if __name__ == "__main__":
737  _test()
738 
739 
740 #Local Variables:
741 #tab-width: 4
742 #end: