python-2.5.2/win32/Lib/Cookie.py
changeset 0 ae805ac0140d
equal deleted inserted replaced
-1:000000000000 0:ae805ac0140d
       
     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 slightly different encoding semantics, 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    >>> C.output()
       
    73    'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
       
    74 
       
    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
       
    79 
       
    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
       
    87 
       
    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.
       
    91 
       
    92    >>> C = Cookie.SmartCookie()
       
    93    >>> C.load("chips=ahoy; vienna=finger")
       
    94    >>> C.output()
       
    95    'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
       
    96 
       
    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.
       
   100 
       
   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;"
       
   105 
       
   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.
       
   109 
       
   110    >>> C = Cookie.SmartCookie()
       
   111    >>> C["oreo"] = "doublestuff"
       
   112    >>> C["oreo"]["path"] = "/"
       
   113    >>> print C
       
   114    Set-Cookie: oreo=doublestuff; Path=/
       
   115 
       
   116 Each dictionary element has a 'value' attribute, which gives you
       
   117 back the value associated with the key.
       
   118 
       
   119    >>> C = Cookie.SmartCookie()
       
   120    >>> C["twix"] = "none for you"
       
   121    >>> C["twix"].value
       
   122    'none for you'
       
   123 
       
   124 
       
   125 A Bit More Advanced
       
   126 -------------------
       
   127 
       
   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.
       
   131 
       
   132 SimpleCookie
       
   133 
       
   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.
       
   137 
       
   138    >>> C = Cookie.SimpleCookie()
       
   139    >>> C["number"] = 7
       
   140    >>> C["string"] = "seven"
       
   141    >>> C["number"].value
       
   142    '7'
       
   143    >>> C["string"].value
       
   144    'seven'
       
   145    >>> C.output()
       
   146    'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
       
   147 
       
   148 
       
   149 SerialCookie
       
   150 
       
   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.)
       
   157 
       
   158    >>> C = Cookie.SerialCookie()
       
   159    >>> C["number"] = 7
       
   160    >>> C["string"] = "seven"
       
   161    >>> C["number"].value
       
   162    7
       
   163    >>> C["string"].value
       
   164    'seven'
       
   165    >>> C.output()
       
   166    'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'
       
   167 
       
   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.
       
   170 
       
   171 
       
   172 SmartCookie
       
   173 
       
   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.
       
   181 
       
   182    >>> C = Cookie.SmartCookie()
       
   183    >>> C["number"] = 7
       
   184    >>> C["string"] = "seven"
       
   185    >>> C["number"].value
       
   186    7
       
   187    >>> C["string"].value
       
   188    'seven'
       
   189    >>> C.output()
       
   190    'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
       
   191 
       
   192 
       
   193 Backwards Compatibility
       
   194 -----------------------
       
   195 
       
   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.
       
   199 
       
   200    >>> C = Cookie.Cookie()
       
   201    >>> print C.__class__.__name__
       
   202    SmartCookie
       
   203 
       
   204 
       
   205 Finis.
       
   206 """  #"
       
   207 #     ^
       
   208 #     |----helps out font-lock
       
   209 
       
   210 #
       
   211 # Import our required modules
       
   212 #
       
   213 import string
       
   214 
       
   215 try:
       
   216     from cPickle import dumps, loads
       
   217 except ImportError:
       
   218     from pickle import dumps, loads
       
   219 
       
   220 import re, warnings
       
   221 
       
   222 __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
       
   223            "SmartCookie","Cookie"]
       
   224 
       
   225 _nulljoin = ''.join
       
   226 _semispacejoin = '; '.join
       
   227 _spacejoin = ' '.join
       
   228 
       
   229 #
       
   230 # Define an exception visible to External modules
       
   231 #
       
   232 class CookieError(Exception):
       
   233     pass
       
   234 
       
   235 
       
   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.
       
   242 #
       
   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
       
   246 #
       
   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',
       
   260 
       
   261     '"' : '\\"',       '\\' : '\\\\',
       
   262 
       
   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'
       
   306     }
       
   307 
       
   308 _idmap = ''.join(chr(x) for x in xrange(256))
       
   309 
       
   310 def _quote(str, LegalChars=_LegalChars,
       
   311            idmap=_idmap, translate=string.translate):
       
   312     #
       
   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.
       
   317     #
       
   318     if "" == translate(str, idmap, LegalChars):
       
   319         return str
       
   320     else:
       
   321         return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
       
   322 # end _quote
       
   323 
       
   324 
       
   325 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
       
   326 _QuotePatt = re.compile(r"[\\].")
       
   327 
       
   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
       
   335 
       
   336     # We have to assume that we must decode this string.
       
   337     # Down to work.
       
   338 
       
   339     # Remove the "s
       
   340     str = str[1:-1]
       
   341 
       
   342     # Check for special sequences.  Examples:
       
   343     #    \012 --> \n
       
   344     #    \"   --> "
       
   345     #
       
   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
       
   369 
       
   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.
       
   376 #
       
   377 
       
   378 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
       
   379 
       
   380 _monthname = [None,
       
   381               'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
       
   382               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
       
   383 
       
   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)
       
   390 
       
   391 
       
   392 #
       
   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.
       
   401 #
       
   402 
       
   403 class Morsel(dict):
       
   404     # RFC 2109 lists these attributes as reserved:
       
   405     #   path       comment         domain
       
   406     #   max-age    secure      version
       
   407     #
       
   408     # For historical reasons, these attributes are also reserved:
       
   409     #   expires
       
   410     #
       
   411     # This dictionary provides a mapping from the lowercase
       
   412     # variant on the left to the appropriate traditional
       
   413     # formatting on the right.
       
   414     _reserved = { "expires" : "expires",
       
   415                    "path"        : "Path",
       
   416                    "comment" : "Comment",
       
   417                    "domain"      : "Domain",
       
   418                    "max-age" : "Max-Age",
       
   419                    "secure"      : "secure",
       
   420                    "version" : "Version",
       
   421                    }
       
   422 
       
   423     def __init__(self):
       
   424         # Set defaults
       
   425         self.key = self.value = self.coded_value = None
       
   426 
       
   427         # Set default attributes
       
   428         for K in self._reserved:
       
   429             dict.__setitem__(self, K, "")
       
   430     # end __init__
       
   431 
       
   432     def __setitem__(self, K, V):
       
   433         K = K.lower()
       
   434         if not K in self._reserved:
       
   435             raise CookieError("Invalid Attribute %s" % K)
       
   436         dict.__setitem__(self, K, V)
       
   437     # end __setitem__
       
   438 
       
   439     def isReservedKey(self, K):
       
   440         return K.lower() in self._reserved
       
   441     # end isReservedKey
       
   442 
       
   443     def set(self, key, val, coded_val,
       
   444             LegalChars=_LegalChars,
       
   445             idmap=_idmap, translate=string.translate):
       
   446         # First we verify that the key isn't a reserved word
       
   447         # Second we make sure it only contains legal characters
       
   448         if key.lower() in self._reserved:
       
   449             raise CookieError("Attempt to set a reserved key: %s" % key)
       
   450         if "" != translate(key, idmap, LegalChars):
       
   451             raise CookieError("Illegal key value: %s" % key)
       
   452 
       
   453         # It's a good key, so save it.
       
   454         self.key                 = key
       
   455         self.value               = val
       
   456         self.coded_value         = coded_val
       
   457     # end set
       
   458 
       
   459     def output(self, attrs=None, header = "Set-Cookie:"):
       
   460         return "%s %s" % ( header, self.OutputString(attrs) )
       
   461 
       
   462     __str__ = output
       
   463 
       
   464     def __repr__(self):
       
   465         return '<%s: %s=%s>' % (self.__class__.__name__,
       
   466                                 self.key, repr(self.value) )
       
   467 
       
   468     def js_output(self, attrs=None):
       
   469         # Print javascript
       
   470         return """
       
   471         <script type="text/javascript">
       
   472         <!-- begin hiding
       
   473         document.cookie = \"%s\";
       
   474         // end hiding -->
       
   475         </script>
       
   476         """ % ( self.OutputString(attrs), )
       
   477     # end js_output()
       
   478 
       
   479     def OutputString(self, attrs=None):
       
   480         # Build up our result
       
   481         #
       
   482         result = []
       
   483         RA = result.append
       
   484 
       
   485         # First, the key=value pair
       
   486         RA("%s=%s" % (self.key, self.coded_value))
       
   487 
       
   488         # Now add any defined attributes
       
   489         if attrs is None:
       
   490             attrs = self._reserved
       
   491         items = self.items()
       
   492         items.sort()
       
   493         for K,V in items:
       
   494             if V == "": continue
       
   495             if K not in attrs: continue
       
   496             if K == "expires" and type(V) == type(1):
       
   497                 RA("%s=%s" % (self._reserved[K], _getdate(V)))
       
   498             elif K == "max-age" and type(V) == type(1):
       
   499                 RA("%s=%d" % (self._reserved[K], V))
       
   500             elif K == "secure":
       
   501                 RA(str(self._reserved[K]))
       
   502             else:
       
   503                 RA("%s=%s" % (self._reserved[K], V))
       
   504 
       
   505         # Return the result
       
   506         return _semispacejoin(result)
       
   507     # end OutputString
       
   508 # end Morsel class
       
   509 
       
   510 
       
   511 
       
   512 #
       
   513 # Pattern for finding cookie
       
   514 #
       
   515 # This used to be strict parsing based on the RFC2109 and RFC2068
       
   516 # specifications.  I have since discovered that MSIE 3.0x doesn't
       
   517 # follow the character rules outlined in those specs.  As a
       
   518 # result, the parsing rules here are less strict.
       
   519 #
       
   520 
       
   521 _LegalCharsPatt  = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
       
   522 _CookiePattern = re.compile(
       
   523     r"(?x)"                       # This is a Verbose pattern
       
   524     r"(?P<key>"                   # Start of group 'key'
       
   525     ""+ _LegalCharsPatt +"+?"     # Any word of at least one letter, nongreedy
       
   526     r")"                          # End of group 'key'
       
   527     r"\s*=\s*"                    # Equal Sign
       
   528     r"(?P<val>"                   # Start of group 'val'
       
   529     r'"(?:[^\\"]|\\.)*"'            # Any doublequoted string
       
   530     r"|"                            # or
       
   531     ""+ _LegalCharsPatt +"*"        # Any word or empty string
       
   532     r")"                          # End of group 'val'
       
   533     r"\s*;?"                      # Probably ending in a semi-colon
       
   534     )
       
   535 
       
   536 
       
   537 # At long last, here is the cookie class.
       
   538 #   Using this class is almost just like using a dictionary.
       
   539 # See this module's docstring for example usage.
       
   540 #
       
   541 class BaseCookie(dict):
       
   542     # A container class for a set of Morsels
       
   543     #
       
   544 
       
   545     def value_decode(self, val):
       
   546         """real_value, coded_value = value_decode(STRING)
       
   547         Called prior to setting a cookie's value from the network
       
   548         representation.  The VALUE is the value read from HTTP
       
   549         header.
       
   550         Override this function to modify the behavior of cookies.
       
   551         """
       
   552         return val, val
       
   553     # end value_encode
       
   554 
       
   555     def value_encode(self, val):
       
   556         """real_value, coded_value = value_encode(VALUE)
       
   557         Called prior to setting a cookie's value from the dictionary
       
   558         representation.  The VALUE is the value being assigned.
       
   559         Override this function to modify the behavior of cookies.
       
   560         """
       
   561         strval = str(val)
       
   562         return strval, strval
       
   563     # end value_encode
       
   564 
       
   565     def __init__(self, input=None):
       
   566         if input: self.load(input)
       
   567     # end __init__
       
   568 
       
   569     def __set(self, key, real_value, coded_value):
       
   570         """Private method for setting a cookie's value"""
       
   571         M = self.get(key, Morsel())
       
   572         M.set(key, real_value, coded_value)
       
   573         dict.__setitem__(self, key, M)
       
   574     # end __set
       
   575 
       
   576     def __setitem__(self, key, value):
       
   577         """Dictionary style assignment."""
       
   578         rval, cval = self.value_encode(value)
       
   579         self.__set(key, rval, cval)
       
   580     # end __setitem__
       
   581 
       
   582     def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
       
   583         """Return a string suitable for HTTP."""
       
   584         result = []
       
   585         items = self.items()
       
   586         items.sort()
       
   587         for K,V in items:
       
   588             result.append( V.output(attrs, header) )
       
   589         return sep.join(result)
       
   590     # end output
       
   591 
       
   592     __str__ = output
       
   593 
       
   594     def __repr__(self):
       
   595         L = []
       
   596         items = self.items()
       
   597         items.sort()
       
   598         for K,V in items:
       
   599             L.append( '%s=%s' % (K,repr(V.value) ) )
       
   600         return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
       
   601 
       
   602     def js_output(self, attrs=None):
       
   603         """Return a string suitable for JavaScript."""
       
   604         result = []
       
   605         items = self.items()
       
   606         items.sort()
       
   607         for K,V in items:
       
   608             result.append( V.js_output(attrs) )
       
   609         return _nulljoin(result)
       
   610     # end js_output
       
   611 
       
   612     def load(self, rawdata):
       
   613         """Load cookies from a string (presumably HTTP_COOKIE) or
       
   614         from a dictionary.  Loading cookies from a dictionary 'd'
       
   615         is equivalent to calling:
       
   616             map(Cookie.__setitem__, d.keys(), d.values())
       
   617         """
       
   618         if type(rawdata) == type(""):
       
   619             self.__ParseString(rawdata)
       
   620         else:
       
   621             self.update(rawdata)
       
   622         return
       
   623     # end load()
       
   624 
       
   625     def __ParseString(self, str, patt=_CookiePattern):
       
   626         i = 0            # Our starting point
       
   627         n = len(str)     # Length of string
       
   628         M = None         # current morsel
       
   629 
       
   630         while 0 <= i < n:
       
   631             # Start looking for a cookie
       
   632             match = patt.search(str, i)
       
   633             if not match: break          # No more cookies
       
   634 
       
   635             K,V = match.group("key"), match.group("val")
       
   636             i = match.end(0)
       
   637 
       
   638             # Parse the key, value in case it's metainfo
       
   639             if K[0] == "$":
       
   640                 # We ignore attributes which pertain to the cookie
       
   641                 # mechanism as a whole.  See RFC 2109.
       
   642                 # (Does anyone care?)
       
   643                 if M:
       
   644                     M[ K[1:] ] = V
       
   645             elif K.lower() in Morsel._reserved:
       
   646                 if M:
       
   647                     M[ K ] = _unquote(V)
       
   648             else:
       
   649                 rval, cval = self.value_decode(V)
       
   650                 self.__set(K, rval, cval)
       
   651                 M = self[K]
       
   652     # end __ParseString
       
   653 # end BaseCookie class
       
   654 
       
   655 class SimpleCookie(BaseCookie):
       
   656     """SimpleCookie
       
   657     SimpleCookie supports strings as cookie values.  When setting
       
   658     the value using the dictionary assignment notation, SimpleCookie
       
   659     calls the builtin str() to convert the value to a string.  Values
       
   660     received from HTTP are kept as strings.
       
   661     """
       
   662     def value_decode(self, val):
       
   663         return _unquote( val ), val
       
   664     def value_encode(self, val):
       
   665         strval = str(val)
       
   666         return strval, _quote( strval )
       
   667 # end SimpleCookie
       
   668 
       
   669 class SerialCookie(BaseCookie):
       
   670     """SerialCookie
       
   671     SerialCookie supports arbitrary objects as cookie values. All
       
   672     values are serialized (using cPickle) before being sent to the
       
   673     client.  All incoming values are assumed to be valid Pickle
       
   674     representations.  IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
       
   675     FORMAT, THEN AN EXCEPTION WILL BE RAISED.
       
   676 
       
   677     Note: Large cookie values add overhead because they must be
       
   678     retransmitted on every HTTP transaction.
       
   679 
       
   680     Note: HTTP has a 2k limit on the size of a cookie.  This class
       
   681     does not check for this limit, so be careful!!!
       
   682     """
       
   683     def __init__(self, input=None):
       
   684         warnings.warn("SerialCookie class is insecure; do not use it",
       
   685                       DeprecationWarning)
       
   686         BaseCookie.__init__(self, input)
       
   687     # end __init__
       
   688     def value_decode(self, val):
       
   689         # This could raise an exception!
       
   690         return loads( _unquote(val) ), val
       
   691     def value_encode(self, val):
       
   692         return val, _quote( dumps(val) )
       
   693 # end SerialCookie
       
   694 
       
   695 class SmartCookie(BaseCookie):
       
   696     """SmartCookie
       
   697     SmartCookie supports arbitrary objects as cookie values.  If the
       
   698     object is a string, then it is quoted.  If the object is not a
       
   699     string, however, then SmartCookie will use cPickle to serialize
       
   700     the object into a string representation.
       
   701 
       
   702     Note: Large cookie values add overhead because they must be
       
   703     retransmitted on every HTTP transaction.
       
   704 
       
   705     Note: HTTP has a 2k limit on the size of a cookie.  This class
       
   706     does not check for this limit, so be careful!!!
       
   707     """
       
   708     def __init__(self, input=None):
       
   709         warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
       
   710                       DeprecationWarning)
       
   711         BaseCookie.__init__(self, input)
       
   712     # end __init__
       
   713     def value_decode(self, val):
       
   714         strval = _unquote(val)
       
   715         try:
       
   716             return loads(strval), val
       
   717         except:
       
   718             return strval, val
       
   719     def value_encode(self, val):
       
   720         if type(val) == type(""):
       
   721             return val, _quote(val)
       
   722         else:
       
   723             return val, _quote( dumps(val) )
       
   724 # end SmartCookie
       
   725 
       
   726 
       
   727 ###########################################################
       
   728 # Backwards Compatibility:  Don't break any existing code!
       
   729 
       
   730 # We provide Cookie() as an alias for SmartCookie()
       
   731 Cookie = SmartCookie
       
   732 
       
   733 #
       
   734 ###########################################################
       
   735 
       
   736 def _test():
       
   737     import doctest, Cookie
       
   738     return doctest.testmod(Cookie)
       
   739 
       
   740 if __name__ == "__main__":
       
   741     _test()
       
   742 
       
   743 
       
   744 #Local Variables:
       
   745 #tab-width: 4
       
   746 #end: