PyXR

c:\python24\lib \ Cookie.py



0001 #!/usr/bin/env python
0002 #
0003 
0004 ####
0005 # Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
0006 #
0007 #                All Rights Reserved
0008 #
0009 # Permission to use, copy, modify, and distribute this software
0010 # and its documentation for any purpose and without fee is hereby
0011 # granted, provided that the above copyright notice appear in all
0012 # copies and that both that copyright notice and this permission
0013 # notice appear in supporting documentation, and that the name of
0014 # Timothy O'Malley  not be used in advertising or publicity
0015 # pertaining to distribution of the software without specific, written
0016 # prior permission.
0017 #
0018 # Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
0019 # SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
0020 # AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
0021 # ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0022 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
0023 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
0024 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
0025 # PERFORMANCE OF THIS SOFTWARE.
0026 #
0027 ####
0028 #
0029 # Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
0030 #   by Timothy O'Malley <timo@alum.mit.edu>
0031 #
0032 #  Cookie.py is a Python module for the handling of HTTP
0033 #  cookies as a Python dictionary.  See RFC 2109 for more
0034 #  information on cookies.
0035 #
0036 #  The original idea to treat Cookies as a dictionary came from
0037 #  Dave Mitchell (davem@magnet.com) in 1995, when he released the
0038 #  first version of nscookie.py.
0039 #
0040 ####
0041 
0042 r"""
0043 Here's a sample session to show how to use this module.
0044 At the moment, this is the only documentation.
0045 
0046 The Basics
0047 ----------
0048 
0049 Importing is easy..
0050 
0051    >>> import Cookie
0052 
0053 Most of the time you start by creating a cookie.  Cookies come in
0054 three flavors, each with slightly different encoding semantics, but
0055 more on that later.
0056 
0057    >>> C = Cookie.SimpleCookie()
0058    >>> C = Cookie.SerialCookie()
0059    >>> C = Cookie.SmartCookie()
0060 
0061 [Note: Long-time users of Cookie.py will remember using
0062 Cookie.Cookie() to create an Cookie object.  Although deprecated, it
0063 is still supported by the code.  See the Backward Compatibility notes
0064 for more information.]
0065 
0066 Once you've created your Cookie, you can add values just as if it were
0067 a dictionary.
0068 
0069    >>> C = Cookie.SmartCookie()
0070    >>> C["fig"] = "newton"
0071    >>> C["sugar"] = "wafer"
0072    >>> print C
0073    Set-Cookie: fig=newton;
0074    Set-Cookie: sugar=wafer;
0075 
0076 Notice that the printable representation of a Cookie is the
0077 appropriate format for a Set-Cookie: header.  This is the
0078 default behavior.  You can change the header and printed
0079 attributes by using the .output() function
0080 
0081    >>> C = Cookie.SmartCookie()
0082    >>> C["rocky"] = "road"
0083    >>> C["rocky"]["path"] = "/cookie"
0084    >>> print C.output(header="Cookie:")
0085    Cookie: rocky=road; Path=/cookie;
0086    >>> print C.output(attrs=[], header="Cookie:")
0087    Cookie: rocky=road;
0088 
0089 The load() method of a Cookie extracts cookies from a string.  In a
0090 CGI script, you would use this method to extract the cookies from the
0091 HTTP_COOKIE environment variable.
0092 
0093    >>> C = Cookie.SmartCookie()
0094    >>> C.load("chips=ahoy; vienna=finger")
0095    >>> print C
0096    Set-Cookie: chips=ahoy;
0097    Set-Cookie: vienna=finger;
0098 
0099 The load() method is darn-tootin smart about identifying cookies
0100 within a string.  Escaped quotation marks, nested semicolons, and other
0101 such trickeries do not confuse it.
0102 
0103    >>> C = Cookie.SmartCookie()
0104    >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
0105    >>> print C
0106    Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;";
0107 
0108 Each element of the Cookie also supports all of the RFC 2109
0109 Cookie attributes.  Here's an example which sets the Path
0110 attribute.
0111 
0112    >>> C = Cookie.SmartCookie()
0113    >>> C["oreo"] = "doublestuff"
0114    >>> C["oreo"]["path"] = "/"
0115    >>> print C
0116    Set-Cookie: oreo=doublestuff; Path=/;
0117 
0118 Each dictionary element has a 'value' attribute, which gives you
0119 back the value associated with the key.
0120 
0121    >>> C = Cookie.SmartCookie()
0122    >>> C["twix"] = "none for you"
0123    >>> C["twix"].value
0124    'none for you'
0125 
0126 
0127 A Bit More Advanced
0128 -------------------
0129 
0130 As mentioned before, there are three different flavors of Cookie
0131 objects, each with different encoding/decoding semantics.  This
0132 section briefly discusses the differences.
0133 
0134 SimpleCookie
0135 
0136 The SimpleCookie expects that all values should be standard strings.
0137 Just to be sure, SimpleCookie invokes the str() builtin to convert
0138 the value to a string, when the values are set dictionary-style.
0139 
0140    >>> C = Cookie.SimpleCookie()
0141    >>> C["number"] = 7
0142    >>> C["string"] = "seven"
0143    >>> C["number"].value
0144    '7'
0145    >>> C["string"].value
0146    'seven'
0147    >>> print C
0148    Set-Cookie: number=7;
0149    Set-Cookie: string=seven;
0150 
0151 
0152 SerialCookie
0153 
0154 The SerialCookie expects that all values should be serialized using
0155 cPickle (or pickle, if cPickle isn't available).  As a result of
0156 serializing, SerialCookie can save almost any Python object to a
0157 value, and recover the exact same object when the cookie has been
0158 returned.  (SerialCookie can yield some strange-looking cookie
0159 values, however.)
0160 
0161    >>> C = Cookie.SerialCookie()
0162    >>> C["number"] = 7
0163    >>> C["string"] = "seven"
0164    >>> C["number"].value
0165    7
0166    >>> C["string"].value
0167    'seven'
0168    >>> print C
0169    Set-Cookie: number="I7\012.";
0170    Set-Cookie: string="S'seven'\012p1\012.";
0171 
0172 Be warned, however, if SerialCookie cannot de-serialize a value (because
0173 it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
0174 
0175 
0176 SmartCookie
0177 
0178 The SmartCookie combines aspects of each of the other two flavors.
0179 When setting a value in a dictionary-fashion, the SmartCookie will
0180 serialize (ala cPickle) the value *if and only if* it isn't a
0181 Python string.  String objects are *not* serialized.  Similarly,
0182 when the load() method parses out values, it attempts to de-serialize
0183 the value.  If it fails, then it fallsback to treating the value
0184 as a string.
0185 
0186    >>> C = Cookie.SmartCookie()
0187    >>> C["number"] = 7
0188    >>> C["string"] = "seven"
0189    >>> C["number"].value
0190    7
0191    >>> C["string"].value
0192    'seven'
0193    >>> print C
0194    Set-Cookie: number="I7\012.";
0195    Set-Cookie: string=seven;
0196 
0197 
0198 Backwards Compatibility
0199 -----------------------
0200 
0201 In order to keep compatibilty with earlier versions of Cookie.py,
0202 it is still possible to use Cookie.Cookie() to create a Cookie.  In
0203 fact, this simply returns a SmartCookie.
0204 
0205    >>> C = Cookie.Cookie()
0206    >>> print C.__class__.__name__
0207    SmartCookie
0208 
0209 
0210 Finis.
0211 """  #"
0212 #     ^
0213 #     |----helps out font-lock
0214 
0215 #
0216 # Import our required modules
0217 #
0218 import string
0219 
0220 try:
0221     from cPickle import dumps, loads
0222 except ImportError:
0223     from pickle import dumps, loads
0224 
0225 import re, warnings
0226 
0227 __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
0228            "SmartCookie","Cookie"]
0229 
0230 _nulljoin = ''.join
0231 _spacejoin = ' '.join
0232 
0233 #
0234 # Define an exception visible to External modules
0235 #
0236 class CookieError(Exception):
0237     pass
0238 
0239 
0240 # These quoting routines conform to the RFC2109 specification, which in
0241 # turn references the character definitions from RFC2068.  They provide
0242 # a two-way quoting algorithm.  Any non-text character is translated
0243 # into a 4 character sequence: a forward-slash followed by the
0244 # three-digit octal equivalent of the character.  Any '\' or '"' is
0245 # quoted with a preceeding '\' slash.
0246 #
0247 # These are taken from RFC2068 and RFC2109.
0248 #       _LegalChars       is the list of chars which don't require "'s
0249 #       _Translator       hash-table for fast quoting
0250 #
0251 _LegalChars       = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
0252 _Translator       = {
0253     '\000' : '\\000',  '\001' : '\\001',  '\002' : '\\002',
0254     '\003' : '\\003',  '\004' : '\\004',  '\005' : '\\005',
0255     '\006' : '\\006',  '\007' : '\\007',  '\010' : '\\010',
0256     '\011' : '\\011',  '\012' : '\\012',  '\013' : '\\013',
0257     '\014' : '\\014',  '\015' : '\\015',  '\016' : '\\016',
0258     '\017' : '\\017',  '\020' : '\\020',  '\021' : '\\021',
0259     '\022' : '\\022',  '\023' : '\\023',  '\024' : '\\024',
0260     '\025' : '\\025',  '\026' : '\\026',  '\027' : '\\027',
0261     '\030' : '\\030',  '\031' : '\\031',  '\032' : '\\032',
0262     '\033' : '\\033',  '\034' : '\\034',  '\035' : '\\035',
0263     '\036' : '\\036',  '\037' : '\\037',
0264 
0265     '"' : '\\"',       '\\' : '\\\\',
0266 
0267     '\177' : '\\177',  '\200' : '\\200',  '\201' : '\\201',
0268     '\202' : '\\202',  '\203' : '\\203',  '\204' : '\\204',
0269     '\205' : '\\205',  '\206' : '\\206',  '\207' : '\\207',
0270     '\210' : '\\210',  '\211' : '\\211',  '\212' : '\\212',
0271     '\213' : '\\213',  '\214' : '\\214',  '\215' : '\\215',
0272     '\216' : '\\216',  '\217' : '\\217',  '\220' : '\\220',
0273     '\221' : '\\221',  '\222' : '\\222',  '\223' : '\\223',
0274     '\224' : '\\224',  '\225' : '\\225',  '\226' : '\\226',
0275     '\227' : '\\227',  '\230' : '\\230',  '\231' : '\\231',
0276     '\232' : '\\232',  '\233' : '\\233',  '\234' : '\\234',
0277     '\235' : '\\235',  '\236' : '\\236',  '\237' : '\\237',
0278     '\240' : '\\240',  '\241' : '\\241',  '\242' : '\\242',
0279     '\243' : '\\243',  '\244' : '\\244',  '\245' : '\\245',
0280     '\246' : '\\246',  '\247' : '\\247',  '\250' : '\\250',
0281     '\251' : '\\251',  '\252' : '\\252',  '\253' : '\\253',
0282     '\254' : '\\254',  '\255' : '\\255',  '\256' : '\\256',
0283     '\257' : '\\257',  '\260' : '\\260',  '\261' : '\\261',
0284     '\262' : '\\262',  '\263' : '\\263',  '\264' : '\\264',
0285     '\265' : '\\265',  '\266' : '\\266',  '\267' : '\\267',
0286     '\270' : '\\270',  '\271' : '\\271',  '\272' : '\\272',
0287     '\273' : '\\273',  '\274' : '\\274',  '\275' : '\\275',
0288     '\276' : '\\276',  '\277' : '\\277',  '\300' : '\\300',
0289     '\301' : '\\301',  '\302' : '\\302',  '\303' : '\\303',
0290     '\304' : '\\304',  '\305' : '\\305',  '\306' : '\\306',
0291     '\307' : '\\307',  '\310' : '\\310',  '\311' : '\\311',
0292     '\312' : '\\312',  '\313' : '\\313',  '\314' : '\\314',
0293     '\315' : '\\315',  '\316' : '\\316',  '\317' : '\\317',
0294     '\320' : '\\320',  '\321' : '\\321',  '\322' : '\\322',
0295     '\323' : '\\323',  '\324' : '\\324',  '\325' : '\\325',
0296     '\326' : '\\326',  '\327' : '\\327',  '\330' : '\\330',
0297     '\331' : '\\331',  '\332' : '\\332',  '\333' : '\\333',
0298     '\334' : '\\334',  '\335' : '\\335',  '\336' : '\\336',
0299     '\337' : '\\337',  '\340' : '\\340',  '\341' : '\\341',
0300     '\342' : '\\342',  '\343' : '\\343',  '\344' : '\\344',
0301     '\345' : '\\345',  '\346' : '\\346',  '\347' : '\\347',
0302     '\350' : '\\350',  '\351' : '\\351',  '\352' : '\\352',
0303     '\353' : '\\353',  '\354' : '\\354',  '\355' : '\\355',
0304     '\356' : '\\356',  '\357' : '\\357',  '\360' : '\\360',
0305     '\361' : '\\361',  '\362' : '\\362',  '\363' : '\\363',
0306     '\364' : '\\364',  '\365' : '\\365',  '\366' : '\\366',
0307     '\367' : '\\367',  '\370' : '\\370',  '\371' : '\\371',
0308     '\372' : '\\372',  '\373' : '\\373',  '\374' : '\\374',
0309     '\375' : '\\375',  '\376' : '\\376',  '\377' : '\\377'
0310     }
0311 
0312 def _quote(str, LegalChars=_LegalChars,
0313            idmap=string._idmap, translate=string.translate):
0314     #
0315     # If the string does not need to be double-quoted,
0316     # then just return the string.  Otherwise, surround
0317     # the string in doublequotes and precede quote (with a \)
0318     # special characters.
0319     #
0320     if "" == translate(str, idmap, LegalChars):
0321         return str
0322     else:
0323         return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
0324 # end _quote
0325 
0326 
0327 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
0328 _QuotePatt = re.compile(r"[\\].")
0329 
0330 def _unquote(str):
0331     # If there aren't any doublequotes,
0332     # then there can't be any special characters.  See RFC 2109.
0333     if  len(str) < 2:
0334         return str
0335     if str[0] != '"' or str[-1] != '"':
0336         return str
0337 
0338     # We have to assume that we must decode this string.
0339     # Down to work.
0340 
0341     # Remove the "s
0342     str = str[1:-1]
0343 
0344     # Check for special sequences.  Examples:
0345     #    \012 --> \n
0346     #    \"   --> "
0347     #
0348     i = 0
0349     n = len(str)
0350     res = []
0351     while 0 <= i < n:
0352         Omatch = _OctalPatt.search(str, i)
0353         Qmatch = _QuotePatt.search(str, i)
0354         if not Omatch and not Qmatch:              # Neither matched
0355             res.append(str[i:])
0356             break
0357         # else:
0358         j = k = -1
0359         if Omatch: j = Omatch.start(0)
0360         if Qmatch: k = Qmatch.start(0)
0361         if Qmatch and ( not Omatch or k < j ):     # QuotePatt matched
0362             res.append(str[i:k])
0363             res.append(str[k+1])
0364             i = k+2
0365         else:                                      # OctalPatt matched
0366             res.append(str[i:j])
0367             res.append( chr( int(str[j+1:j+4], 8) ) )
0368             i = j+4
0369     return _nulljoin(res)
0370 # end _unquote
0371 
0372 # The _getdate() routine is used to set the expiration time in
0373 # the cookie's HTTP header.      By default, _getdate() returns the
0374 # current time in the appropriate "expires" format for a
0375 # Set-Cookie header.     The one optional argument is an offset from
0376 # now, in seconds.      For example, an offset of -3600 means "one hour ago".
0377 # The offset may be a floating point number.
0378 #
0379 
0380 _weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
0381 
0382 _monthname = [None,
0383               'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
0384               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
0385 
0386 def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
0387     from time import gmtime, time
0388     now = time()
0389     year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
0390     return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
0391            (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
0392 
0393 
0394 #
0395 # A class to hold ONE key,value pair.
0396 # In a cookie, each such pair may have several attributes.
0397 #       so this class is used to keep the attributes associated
0398 #       with the appropriate key,value pair.
0399 # This class also includes a coded_value attribute, which
0400 #       is used to hold the network representation of the
0401 #       value.  This is most useful when Python objects are
0402 #       pickled for network transit.
0403 #
0404 
0405 class Morsel(dict):
0406     # RFC 2109 lists these attributes as reserved:
0407     #   path       comment         domain
0408     #   max-age    secure      version
0409     #
0410     # For historical reasons, these attributes are also reserved:
0411     #   expires
0412     #
0413     # This dictionary provides a mapping from the lowercase
0414     # variant on the left to the appropriate traditional
0415     # formatting on the right.
0416     _reserved = { "expires" : "expires",
0417                    "path"        : "Path",
0418                    "comment" : "Comment",
0419                    "domain"      : "Domain",
0420                    "max-age" : "Max-Age",
0421                    "secure"      : "secure",
0422                    "version" : "Version",
0423                    }
0424 
0425     def __init__(self):
0426         # Set defaults
0427         self.key = self.value = self.coded_value = None
0428 
0429         # Set default attributes
0430         for K in self._reserved:
0431             dict.__setitem__(self, K, "")
0432     # end __init__
0433 
0434     def __setitem__(self, K, V):
0435         K = K.lower()
0436         if not K in self._reserved:
0437             raise CookieError("Invalid Attribute %s" % K)
0438         dict.__setitem__(self, K, V)
0439     # end __setitem__
0440 
0441     def isReservedKey(self, K):
0442         return K.lower() in self._reserved
0443     # end isReservedKey
0444 
0445     def set(self, key, val, coded_val,
0446             LegalChars=_LegalChars,
0447             idmap=string._idmap, translate=string.translate ):
0448         # First we verify that the key isn't a reserved word
0449         # Second we make sure it only contains legal characters
0450         if key.lower() in self._reserved:
0451             raise CookieError("Attempt to set a reserved key: %s" % key)
0452         if "" != translate(key, idmap, LegalChars):
0453             raise CookieError("Illegal key value: %s" % key)
0454 
0455         # It's a good key, so save it.
0456         self.key                 = key
0457         self.value               = val
0458         self.coded_value         = coded_val
0459     # end set
0460 
0461     def output(self, attrs=None, header = "Set-Cookie:"):
0462         return "%s %s" % ( header, self.OutputString(attrs) )
0463 
0464     __str__ = output
0465 
0466     def __repr__(self):
0467         return '<%s: %s=%s>' % (self.__class__.__name__,
0468                                 self.key, repr(self.value) )
0469 
0470     def js_output(self, attrs=None):
0471         # Print javascript
0472         return """
0473         <SCRIPT LANGUAGE="JavaScript">
0474         <!-- begin hiding
0475         document.cookie = \"%s\"
0476         // end hiding -->
0477         </script>
0478         """ % ( self.OutputString(attrs), )
0479     # end js_output()
0480 
0481     def OutputString(self, attrs=None):
0482         # Build up our result
0483         #
0484         result = []
0485         RA = result.append
0486 
0487         # First, the key=value pair
0488         RA("%s=%s;" % (self.key, self.coded_value))
0489 
0490         # Now add any defined attributes
0491         if attrs is None:
0492             attrs = self._reserved
0493         items = self.items()
0494         items.sort()
0495         for K,V in items:
0496             if V == "": continue
0497             if K not in attrs: continue
0498             if K == "expires" and type(V) == type(1):
0499                 RA("%s=%s;" % (self._reserved[K], _getdate(V)))
0500             elif K == "max-age" and type(V) == type(1):
0501                 RA("%s=%d;" % (self._reserved[K], V))
0502             elif K == "secure":
0503                 RA("%s;" % self._reserved[K])
0504             else:
0505                 RA("%s=%s;" % (self._reserved[K], V))
0506 
0507         # Return the result
0508         return _spacejoin(result)
0509     # end OutputString
0510 # end Morsel class
0511 
0512 
0513 
0514 #
0515 # Pattern for finding cookie
0516 #
0517 # This used to be strict parsing based on the RFC2109 and RFC2068
0518 # specifications.  I have since discovered that MSIE 3.0x doesn't
0519 # follow the character rules outlined in those specs.  As a
0520 # result, the parsing rules here are less strict.
0521 #
0522 
0523 _LegalCharsPatt  = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
0524 _CookiePattern = re.compile(
0525     r"(?x)"                       # This is a Verbose pattern
0526     r"(?P<key>"                   # Start of group 'key'
0527     ""+ _LegalCharsPatt +"+?"     # Any word of at least one letter, nongreedy
0528     r")"                          # End of group 'key'
0529     r"\s*=\s*"                    # Equal Sign
0530     r"(?P<val>"                   # Start of group 'val'
0531     r'"(?:[^\\"]|\\.)*"'            # Any doublequoted string
0532     r"|"                            # or
0533     ""+ _LegalCharsPatt +"*"        # Any word or empty string
0534     r")"                          # End of group 'val'
0535     r"\s*;?"                      # Probably ending in a semi-colon
0536     )
0537 
0538 
0539 # At long last, here is the cookie class.
0540 #   Using this class is almost just like using a dictionary.
0541 # See this module's docstring for example usage.
0542 #
0543 class BaseCookie(dict):
0544     # A container class for a set of Morsels
0545     #
0546 
0547     def value_decode(self, val):
0548         """real_value, coded_value = value_decode(STRING)
0549         Called prior to setting a cookie's value from the network
0550         representation.  The VALUE is the value read from HTTP
0551         header.
0552         Override this function to modify the behavior of cookies.
0553         """
0554         return val, val
0555     # end value_encode
0556 
0557     def value_encode(self, val):
0558         """real_value, coded_value = value_encode(VALUE)
0559         Called prior to setting a cookie's value from the dictionary
0560         representation.  The VALUE is the value being assigned.
0561         Override this function to modify the behavior of cookies.
0562         """
0563         strval = str(val)
0564         return strval, strval
0565     # end value_encode
0566 
0567     def __init__(self, input=None):
0568         if input: self.load(input)
0569     # end __init__
0570 
0571     def __set(self, key, real_value, coded_value):
0572         """Private method for setting a cookie's value"""
0573         M = self.get(key, Morsel())
0574         M.set(key, real_value, coded_value)
0575         dict.__setitem__(self, key, M)
0576     # end __set
0577 
0578     def __setitem__(self, key, value):
0579         """Dictionary style assignment."""
0580         rval, cval = self.value_encode(value)
0581         self.__set(key, rval, cval)
0582     # end __setitem__
0583 
0584     def output(self, attrs=None, header="Set-Cookie:", sep="\n"):
0585         """Return a string suitable for HTTP."""
0586         result = []
0587         items = self.items()
0588         items.sort()
0589         for K,V in items:
0590             result.append( V.output(attrs, header) )
0591         return sep.join(result)
0592     # end output
0593 
0594     __str__ = output
0595 
0596     def __repr__(self):
0597         L = []
0598         items = self.items()
0599         items.sort()
0600         for K,V in items:
0601             L.append( '%s=%s' % (K,repr(V.value) ) )
0602         return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
0603 
0604     def js_output(self, attrs=None):
0605         """Return a string suitable for JavaScript."""
0606         result = []
0607         items = self.items()
0608         items.sort()
0609         for K,V in items:
0610             result.append( V.js_output(attrs) )
0611         return _nulljoin(result)
0612     # end js_output
0613 
0614     def load(self, rawdata):
0615         """Load cookies from a string (presumably HTTP_COOKIE) or
0616         from a dictionary.  Loading cookies from a dictionary 'd'
0617         is equivalent to calling:
0618             map(Cookie.__setitem__, d.keys(), d.values())
0619         """
0620         if type(rawdata) == type(""):
0621             self.__ParseString(rawdata)
0622         else:
0623             self.update(rawdata)
0624         return
0625     # end load()
0626 
0627     def __ParseString(self, str, patt=_CookiePattern):
0628         i = 0            # Our starting point
0629         n = len(str)     # Length of string
0630         M = None         # current morsel
0631 
0632         while 0 <= i < n:
0633             # Start looking for a cookie
0634             match = patt.search(str, i)
0635             if not match: break          # No more cookies
0636 
0637             K,V = match.group("key"), match.group("val")
0638             i = match.end(0)
0639 
0640             # Parse the key, value in case it's metainfo
0641             if K[0] == "$":
0642                 # We ignore attributes which pertain to the cookie
0643                 # mechanism as a whole.  See RFC 2109.
0644                 # (Does anyone care?)
0645                 if M:
0646                     M[ K[1:] ] = V
0647             elif K.lower() in Morsel._reserved:
0648                 if M:
0649                     M[ K ] = _unquote(V)
0650             else:
0651                 rval, cval = self.value_decode(V)
0652                 self.__set(K, rval, cval)
0653                 M = self[K]
0654     # end __ParseString
0655 # end BaseCookie class
0656 
0657 class SimpleCookie(BaseCookie):
0658     """SimpleCookie
0659     SimpleCookie supports strings as cookie values.  When setting
0660     the value using the dictionary assignment notation, SimpleCookie
0661     calls the builtin str() to convert the value to a string.  Values
0662     received from HTTP are kept as strings.
0663     """
0664     def value_decode(self, val):
0665         return _unquote( val ), val
0666     def value_encode(self, val):
0667         strval = str(val)
0668         return strval, _quote( strval )
0669 # end SimpleCookie
0670 
0671 class SerialCookie(BaseCookie):
0672     """SerialCookie
0673     SerialCookie supports arbitrary objects as cookie values. All
0674     values are serialized (using cPickle) before being sent to the
0675     client.  All incoming values are assumed to be valid Pickle
0676     representations.  IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
0677     FORMAT, THEN AN EXCEPTION WILL BE RAISED.
0678 
0679     Note: Large cookie values add overhead because they must be
0680     retransmitted on every HTTP transaction.
0681 
0682     Note: HTTP has a 2k limit on the size of a cookie.  This class
0683     does not check for this limit, so be careful!!!
0684     """
0685     def __init__(self, input=None):
0686         warnings.warn("SerialCookie class is insecure; do not use it",
0687                       DeprecationWarning)
0688         BaseCookie.__init__(self, input)
0689     # end __init__
0690     def value_decode(self, val):
0691         # This could raise an exception!
0692         return loads( _unquote(val) ), val
0693     def value_encode(self, val):
0694         return val, _quote( dumps(val) )
0695 # end SerialCookie
0696 
0697 class SmartCookie(BaseCookie):
0698     """SmartCookie
0699     SmartCookie supports arbitrary objects as cookie values.  If the
0700     object is a string, then it is quoted.  If the object is not a
0701     string, however, then SmartCookie will use cPickle to serialize
0702     the object into a string representation.
0703 
0704     Note: Large cookie values add overhead because they must be
0705     retransmitted on every HTTP transaction.
0706 
0707     Note: HTTP has a 2k limit on the size of a cookie.  This class
0708     does not check for this limit, so be careful!!!
0709     """
0710     def __init__(self, input=None):
0711         warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
0712                       DeprecationWarning)
0713         BaseCookie.__init__(self, input)
0714     # end __init__
0715     def value_decode(self, val):
0716         strval = _unquote(val)
0717         try:
0718             return loads(strval), val
0719         except:
0720             return strval, val
0721     def value_encode(self, val):
0722         if type(val) == type(""):
0723             return val, _quote(val)
0724         else:
0725             return val, _quote( dumps(val) )
0726 # end SmartCookie
0727 
0728 
0729 ###########################################################
0730 # Backwards Compatibility:  Don't break any existing code!
0731 
0732 # We provide Cookie() as an alias for SmartCookie()
0733 Cookie = SmartCookie
0734 
0735 #
0736 ###########################################################
0737 
0738 def _test():
0739     import doctest, Cookie
0740     return doctest.testmod(Cookie)
0741 
0742 if __name__ == "__main__":
0743     _test()
0744 
0745 
0746 #Local Variables:
0747 #tab-width: 4
0748 #end:
0749 

Generated by PyXR 0.9.4
SourceForge.net Logo