ยปCore Development>Code coverage>Lib/Cookie.py

Python code coverage for Lib/Cookie.py

#countcontent
1n/a#!/usr/bin/env python
2n/a#
3n/a
4n/a####
5n/a# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
6n/a#
7n/a# All Rights Reserved
8n/a#
9n/a# Permission to use, copy, modify, and distribute this software
10n/a# and its documentation for any purpose and without fee is hereby
11n/a# granted, provided that the above copyright notice appear in all
12n/a# copies and that both that copyright notice and this permission
13n/a# notice appear in supporting documentation, and that the name of
14n/a# Timothy O'Malley not be used in advertising or publicity
15n/a# pertaining to distribution of the software without specific, written
16n/a# prior permission.
17n/a#
18n/a# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
19n/a# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
20n/a# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
21n/a# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
22n/a# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23n/a# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
24n/a# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
25n/a# PERFORMANCE OF THIS SOFTWARE.
26n/a#
27n/a####
28n/a#
29n/a# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
30n/a# by Timothy O'Malley <timo@alum.mit.edu>
31n/a#
32n/a# Cookie.py is a Python module for the handling of HTTP
33n/a# cookies as a Python dictionary. See RFC 2109 for more
34n/a# information on cookies.
35n/a#
36n/a# The original idea to treat Cookies as a dictionary came from
37n/a# Dave Mitchell (davem@magnet.com) in 1995, when he released the
38n/a# first version of nscookie.py.
39n/a#
40n/a####
41n/a
42n/ar"""
43n/aHere's a sample session to show how to use this module.
44n/aAt the moment, this is the only documentation.
45n/a
46n/aThe Basics
47n/a----------
48n/a
49n/aImporting is easy..
50n/a
51n/a >>> import Cookie
52n/a
53n/aMost of the time you start by creating a cookie. Cookies come in
54n/athree flavors, each with slightly different encoding semantics, but
55n/amore on that later.
56n/a
57n/a >>> C = Cookie.SimpleCookie()
58n/a >>> C = Cookie.SerialCookie()
59n/a >>> C = Cookie.SmartCookie()
60n/a
61n/a[Note: Long-time users of Cookie.py will remember using
62n/aCookie.Cookie() to create an Cookie object. Although deprecated, it
63n/ais still supported by the code. See the Backward Compatibility notes
64n/afor more information.]
65n/a
66n/aOnce you've created your Cookie, you can add values just as if it were
67n/aa dictionary.
68n/a
69n/a >>> C = Cookie.SmartCookie()
70n/a >>> C["fig"] = "newton"
71n/a >>> C["sugar"] = "wafer"
72n/a >>> C.output()
73n/a 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
74n/a
75n/aNotice that the printable representation of a Cookie is the
76n/aappropriate format for a Set-Cookie: header. This is the
77n/adefault behavior. You can change the header and printed
78n/aattributes by using the .output() function
79n/a
80n/a >>> C = Cookie.SmartCookie()
81n/a >>> C["rocky"] = "road"
82n/a >>> C["rocky"]["path"] = "/cookie"
83n/a >>> print C.output(header="Cookie:")
84n/a Cookie: rocky=road; Path=/cookie
85n/a >>> print C.output(attrs=[], header="Cookie:")
86n/a Cookie: rocky=road
87n/a
88n/aThe load() method of a Cookie extracts cookies from a string. In a
89n/aCGI script, you would use this method to extract the cookies from the
90n/aHTTP_COOKIE environment variable.
91n/a
92n/a >>> C = Cookie.SmartCookie()
93n/a >>> C.load("chips=ahoy; vienna=finger")
94n/a >>> C.output()
95n/a 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
96n/a
97n/aThe load() method is darn-tootin smart about identifying cookies
98n/awithin a string. Escaped quotation marks, nested semicolons, and other
99n/asuch trickeries do not confuse it.
100n/a
101n/a >>> C = Cookie.SmartCookie()
102n/a >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
103n/a >>> print C
104n/a Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
105n/a
106n/aEach element of the Cookie also supports all of the RFC 2109
107n/aCookie attributes. Here's an example which sets the Path
108n/aattribute.
109n/a
110n/a >>> C = Cookie.SmartCookie()
111n/a >>> C["oreo"] = "doublestuff"
112n/a >>> C["oreo"]["path"] = "/"
113n/a >>> print C
114n/a Set-Cookie: oreo=doublestuff; Path=/
115n/a
116n/aEach dictionary element has a 'value' attribute, which gives you
117n/aback the value associated with the key.
118n/a
119n/a >>> C = Cookie.SmartCookie()
120n/a >>> C["twix"] = "none for you"
121n/a >>> C["twix"].value
122n/a 'none for you'
123n/a
124n/a
125n/aA Bit More Advanced
126n/a-------------------
127n/a
128n/aAs mentioned before, there are three different flavors of Cookie
129n/aobjects, each with different encoding/decoding semantics. This
130n/asection briefly discusses the differences.
131n/a
132n/aSimpleCookie
133n/a
134n/aThe SimpleCookie expects that all values should be standard strings.
135n/aJust to be sure, SimpleCookie invokes the str() builtin to convert
136n/athe value to a string, when the values are set dictionary-style.
137n/a
138n/a >>> C = Cookie.SimpleCookie()
139n/a >>> C["number"] = 7
140n/a >>> C["string"] = "seven"
141n/a >>> C["number"].value
142n/a '7'
143n/a >>> C["string"].value
144n/a 'seven'
145n/a >>> C.output()
146n/a 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
147n/a
148n/a
149n/aSerialCookie
150n/a
151n/aThe SerialCookie expects that all values should be serialized using
152n/acPickle (or pickle, if cPickle isn't available). As a result of
153n/aserializing, SerialCookie can save almost any Python object to a
154n/avalue, and recover the exact same object when the cookie has been
155n/areturned. (SerialCookie can yield some strange-looking cookie
156n/avalues, however.)
157n/a
158n/a >>> C = Cookie.SerialCookie()
159n/a >>> C["number"] = 7
160n/a >>> C["string"] = "seven"
161n/a >>> C["number"].value
162n/a 7
163n/a >>> C["string"].value
164n/a 'seven'
165n/a >>> C.output()
166n/a 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'
167n/a
168n/aBe warned, however, if SerialCookie cannot de-serialize a value (because
169n/ait isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
170n/a
171n/a
172n/aSmartCookie
173n/a
174n/aThe SmartCookie combines aspects of each of the other two flavors.
175n/aWhen setting a value in a dictionary-fashion, the SmartCookie will
176n/aserialize (ala cPickle) the value *if and only if* it isn't a
177n/aPython string. String objects are *not* serialized. Similarly,
178n/awhen the load() method parses out values, it attempts to de-serialize
179n/athe value. If it fails, then it fallsback to treating the value
180n/aas a string.
181n/a
182n/a >>> C = Cookie.SmartCookie()
183n/a >>> C["number"] = 7
184n/a >>> C["string"] = "seven"
185n/a >>> C["number"].value
186n/a 7
187n/a >>> C["string"].value
188n/a 'seven'
189n/a >>> C.output()
190n/a 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
191n/a
192n/a
193n/aBackwards Compatibility
194n/a-----------------------
195n/a
196n/aIn order to keep compatibilty with earlier versions of Cookie.py,
197n/ait is still possible to use Cookie.Cookie() to create a Cookie. In
198n/afact, this simply returns a SmartCookie.
199n/a
200n/a >>> C = Cookie.Cookie()
201n/a >>> print C.__class__.__name__
202n/a SmartCookie
203n/a
204n/a
205n/aFinis.
2061""" #"
207n/a# ^
208n/a# |----helps out font-lock
209n/a
210n/a#
211n/a# Import our required modules
212n/a#
2131import string
214n/a
2151try:
2161 from cPickle import dumps, loads
2170except ImportError:
2180 from pickle import dumps, loads
219n/a
2201import re, warnings
221n/a
2221__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
2231 "SmartCookie","Cookie"]
224n/a
2251_nulljoin = ''.join
2261_semispacejoin = '; '.join
2271_spacejoin = ' '.join
228n/a
229n/a#
230n/a# Define an exception visible to External modules
231n/a#
2322class CookieError(Exception):
2331 pass
234n/a
235n/a
236n/a# These quoting routines conform to the RFC2109 specification, which in
237n/a# turn references the character definitions from RFC2068. They provide
238n/a# a two-way quoting algorithm. Any non-text character is translated
239n/a# into a 4 character sequence: a forward-slash followed by the
240n/a# three-digit octal equivalent of the character. Any '\' or '"' is
241n/a# quoted with a preceeding '\' slash.
242n/a#
243n/a# These are taken from RFC2068 and RFC2109.
244n/a# _LegalChars is the list of chars which don't require "'s
245n/a# _Translator hash-table for fast quoting
246n/a#
2471_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
2481_Translator = {
2491 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
2501 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
2511 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
2521 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
2531 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
2541 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
2551 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
2561 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
2571 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
2581 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
2591 '\036' : '\\036', '\037' : '\\037',
260n/a
2611 '"' : '\\"', '\\' : '\\\\',
262n/a
2631 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
2641 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
2651 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
2661 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
2671 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
2681 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
2691 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
2701 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
2711 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
2721 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
2731 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
2741 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
2751 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
2761 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
2771 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
2781 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
2791 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
2801 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
2811 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
2821 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
2831 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
2841 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
2851 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
2861 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
2871 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
2881 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
2891 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
2901 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
2911 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
2921 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
2931 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
2941 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
2951 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
2961 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
2971 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
2981 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
2991 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
3001 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
3011 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
3021 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
3031 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
3041 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
3051 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
306n/a }
307n/a
308258_idmap = ''.join(chr(x) for x in xrange(256))
309n/a
3101def _quote(str, LegalChars=_LegalChars,
3111 idmap=_idmap, translate=string.translate):
312n/a #
313n/a # If the string does not need to be double-quoted,
314n/a # then just return the string. Otherwise, surround
315n/a # the string in doublequotes and precede quote (with a \)
316n/a # special characters.
317n/a #
31811 if "" == translate(str, idmap, LegalChars):
3197 return str
320n/a else:
3214 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
322n/a# end _quote
323n/a
324n/a
3251_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
3261_QuotePatt = re.compile(r"[\\].")
327n/a
3281def _unquote(str):
329n/a # If there aren't any doublequotes,
330n/a # then there can't be any special characters. See RFC 2109.
33113 if len(str) < 2:
3321 return str
33312 if str[0] != '"' or str[-1] != '"':
3346 return str
335n/a
336n/a # We have to assume that we must decode this string.
337n/a # Down to work.
338n/a
339n/a # Remove the "s
3406 str = str[1:-1]
341n/a
342n/a # Check for special sequences. Examples:
343n/a # \012 --> \n
344n/a # \" --> "
345n/a #
3466 i = 0
3476 n = len(str)
3486 res = []
34912 while 0 <= i < n:
35012 Omatch = _OctalPatt.search(str, i)
35112 Qmatch = _QuotePatt.search(str, i)
35212 if not Omatch and not Qmatch: # Neither matched
3536 res.append(str[i:])
3546 break
355n/a # else:
3566 j = k = -1
3576 if Omatch: j = Omatch.start(0)
3586 if Qmatch: k = Qmatch.start(0)
3596 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
3604 res.append(str[i:k])
3614 res.append(str[k+1])
3624 i = k+2
363n/a else: # OctalPatt matched
3642 res.append(str[i:j])
3652 res.append( chr( int(str[j+1:j+4], 8) ) )
3662 i = j+4
3676 return _nulljoin(res)
368n/a# end _unquote
369n/a
370n/a# The _getdate() routine is used to set the expiration time in
371n/a# the cookie's HTTP header. By default, _getdate() returns the
372n/a# current time in the appropriate "expires" format for a
373n/a# Set-Cookie header. The one optional argument is an offset from
374n/a# now, in seconds. For example, an offset of -3600 means "one hour ago".
375n/a# The offset may be a floating point number.
376n/a#
377n/a
3781_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
379n/a
3801_monthname = [None,
3811 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
3821 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
383n/a
3841def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
3850 from time import gmtime, time
3860 now = time()
3870 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
3880 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
3890 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
390n/a
391n/a
392n/a#
393n/a# A class to hold ONE key,value pair.
394n/a# In a cookie, each such pair may have several attributes.
395n/a# so this class is used to keep the attributes associated
396n/a# with the appropriate key,value pair.
397n/a# This class also includes a coded_value attribute, which
398n/a# is used to hold the network representation of the
399n/a# value. This is most useful when Python objects are
400n/a# pickled for network transit.
401n/a#
402n/a
4032class Morsel(dict):
404n/a # RFC 2109 lists these attributes as reserved:
405n/a # path comment domain
406n/a # max-age secure version
407n/a #
408n/a # For historical reasons, these attributes are also reserved:
409n/a # expires
410n/a #
411n/a # This is an extension from Microsoft:
412n/a # httponly
413n/a #
414n/a # This dictionary provides a mapping from the lowercase
415n/a # variant on the left to the appropriate traditional
416n/a # formatting on the right.
4171 _reserved = { "expires" : "expires",
4181 "path" : "Path",
4191 "comment" : "Comment",
4201 "domain" : "Domain",
4211 "max-age" : "Max-Age",
4221 "secure" : "secure",
4231 "httponly" : "httponly",
4241 "version" : "Version",
425n/a }
426n/a
4271 def __init__(self):
428n/a # Set defaults
42920 self.key = self.value = self.coded_value = None
430n/a
431n/a # Set default attributes
432180 for K in self._reserved:
433160 dict.__setitem__(self, K, "")
434n/a # end __init__
435n/a
4361 def __setitem__(self, K, V):
4376 K = K.lower()
4386 if not K in self._reserved:
4390 raise CookieError("Invalid Attribute %s" % K)
4406 dict.__setitem__(self, K, V)
441n/a # end __setitem__
442n/a
4431 def isReservedKey(self, K):
4440 return K.lower() in self._reserved
445n/a # end isReservedKey
446n/a
447n/a def set(self, key, val, coded_val,
4481 LegalChars=_LegalChars,
4491 idmap=_idmap, translate=string.translate):
450n/a # First we verify that the key isn't a reserved word
451n/a # Second we make sure it only contains legal characters
45220 if key.lower() in self._reserved:
4530 raise CookieError("Attempt to set a reserved key: %s" % key)
45420 if "" != translate(key, idmap, LegalChars):
4550 raise CookieError("Illegal key value: %s" % key)
456n/a
457n/a # It's a good key, so save it.
45820 self.key = key
45920 self.value = val
46020 self.coded_value = coded_val
461n/a # end set
462n/a
4631 def output(self, attrs=None, header = "Set-Cookie:"):
46419 return "%s %s" % ( header, self.OutputString(attrs) )
465n/a
4661 __str__ = output
467n/a
4681 def __repr__(self):
4690 return '<%s: %s=%s>' % (self.__class__.__name__,
4700 self.key, repr(self.value) )
471n/a
4721 def js_output(self, attrs=None):
473n/a # Print javascript
474n/a return """
475n/a <script type="text/javascript">
476n/a <!-- begin hiding
477n/a document.cookie = \"%s\";
478n/a // end hiding -->
479n/a </script>
4802 """ % ( self.OutputString(attrs).replace('"',r'\"'), )
481n/a # end js_output()
482n/a
4831 def OutputString(self, attrs=None):
484n/a # Build up our result
485n/a #
48621 result = []
48721 RA = result.append
488n/a
489n/a # First, the key=value pair
49021 RA("%s=%s" % (self.key, self.coded_value))
491n/a
492n/a # Now add any defined attributes
49321 if attrs is None:
49418 attrs = self._reserved
49521 items = self.items()
49621 items.sort()
497189 for K,V in items:
498168 if V == "": continue
4999 if K not in attrs: continue
5006 if K == "expires" and type(V) == type(1):
5010 RA("%s=%s" % (self._reserved[K], _getdate(V)))
5026 elif K == "max-age" and type(V) == type(1):
5030 RA("%s=%d" % (self._reserved[K], V))
5046 elif K == "secure":
5050 RA(str(self._reserved[K]))
5066 elif K == "httponly":
5070 RA(str(self._reserved[K]))
508n/a else:
5096 RA("%s=%s" % (self._reserved[K], V))
510n/a
511n/a # Return the result
51221 return _semispacejoin(result)
513n/a # end OutputString
514n/a# end Morsel class
515n/a
516n/a
517n/a
518n/a#
519n/a# Pattern for finding cookie
520n/a#
521n/a# This used to be strict parsing based on the RFC2109 and RFC2068
522n/a# specifications. I have since discovered that MSIE 3.0x doesn't
523n/a# follow the character rules outlined in those specs. As a
524n/a# result, the parsing rules here are less strict.
525n/a#
526n/a
5271_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
5281_CookiePattern = re.compile(
529n/a r"(?x)" # This is a Verbose pattern
530n/a r"(?P<key>" # Start of group 'key'
531n/a ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
532n/a r")" # End of group 'key'
533n/a r"\s*=\s*" # Equal Sign
534n/a r"(?P<val>" # Start of group 'val'
535n/a r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
536n/a r"|" # or
5371 ""+ _LegalCharsPatt +"*" # Any word or empty string
538n/a r")" # End of group 'val'
539n/a r"\s*;?" # Probably ending in a semi-colon
540n/a )
541n/a
542n/a
543n/a# At long last, here is the cookie class.
544n/a# Using this class is almost just like using a dictionary.
545n/a# See this module's docstring for example usage.
546n/a#
5472class BaseCookie(dict):
548n/a # A container class for a set of Morsels
549n/a #
550n/a
5511 def value_decode(self, val):
552n/a """real_value, coded_value = value_decode(STRING)
553n/a Called prior to setting a cookie's value from the network
554n/a representation. The VALUE is the value read from HTTP
555n/a header.
556n/a Override this function to modify the behavior of cookies.
557n/a """
5580 return val, val
559n/a # end value_encode
560n/a
5611 def value_encode(self, val):
562n/a """real_value, coded_value = value_encode(VALUE)
563n/a Called prior to setting a cookie's value from the dictionary
564n/a representation. The VALUE is the value being assigned.
565n/a Override this function to modify the behavior of cookies.
566n/a """
5670 strval = str(val)
5680 return strval, strval
569n/a # end value_encode
570n/a
5711 def __init__(self, input=None):
57218 if input: self.load(input)
573n/a # end __init__
574n/a
5751 def __set(self, key, real_value, coded_value):
576n/a """Private method for setting a cookie's value"""
57720 M = self.get(key, Morsel())
57820 M.set(key, real_value, coded_value)
57920 dict.__setitem__(self, key, M)
580n/a # end __set
581n/a
5821 def __setitem__(self, key, value):
583n/a """Dictionary style assignment."""
58411 rval, cval = self.value_encode(value)
58511 self.__set(key, rval, cval)
586n/a # end __setitem__
587n/a
5881 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
589n/a """Return a string suitable for HTTP."""
59013 result = []
59113 items = self.items()
59213 items.sort()
59332 for K,V in items:
59419 result.append( V.output(attrs, header) )
59513 return sep.join(result)
596n/a # end output
597n/a
5981 __str__ = output
599n/a
6001 def __repr__(self):
6013 L = []
6023 items = self.items()
6033 items.sort()
6047 for K,V in items:
6054 L.append( '%s=%s' % (K,repr(V.value) ) )
6063 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
607n/a
6081 def js_output(self, attrs=None):
609n/a """Return a string suitable for JavaScript."""
6102 result = []
6112 items = self.items()
6122 items.sort()
6134 for K,V in items:
6142 result.append( V.js_output(attrs) )
6152 return _nulljoin(result)
616n/a # end js_output
617n/a
6181 def load(self, rawdata):
619n/a """Load cookies from a string (presumably HTTP_COOKIE) or
620n/a from a dictionary. Loading cookies from a dictionary 'd'
621n/a is equivalent to calling:
622n/a map(Cookie.__setitem__, d.keys(), d.values())
623n/a """
6247 if type(rawdata) == type(""):
6257 self.__ParseString(rawdata)
626n/a else:
627n/a # self.update() wouldn't call our custom __setitem__
6280 for k, v in rawdata.items():
6290 self[k] = v
6307 return
631n/a # end load()
632n/a
6331 def __ParseString(self, str, patt=_CookiePattern):
6347 i = 0 # Our starting point
6357 n = len(str) # Length of string
6367 M = None # current morsel
637n/a
63820 while 0 <= i < n:
639n/a # Start looking for a cookie
64013 match = patt.search(str, i)
64113 if not match: break # No more cookies
642n/a
64313 K,V = match.group("key"), match.group("val")
64413 i = match.end(0)
645n/a
646n/a # Parse the key, value in case it's metainfo
64713 if K[0] == "$":
648n/a # We ignore attributes which pertain to the cookie
649n/a # mechanism as a whole. See RFC 2109.
650n/a # (Does anyone care?)
6510 if M:
6520 M[ K[1:] ] = V
65313 elif K.lower() in Morsel._reserved:
6544 if M:
6554 M[ K ] = _unquote(V)
656n/a else:
6579 rval, cval = self.value_decode(V)
6589 self.__set(K, rval, cval)
6599 M = self[K]
660n/a # end __ParseString
661n/a# end BaseCookie class
662n/a
6632class SimpleCookie(BaseCookie):
664n/a """SimpleCookie
665n/a SimpleCookie supports strings as cookie values. When setting
666n/a the value using the dictionary assignment notation, SimpleCookie
667n/a calls the builtin str() to convert the value to a string. Values
668n/a received from HTTP are kept as strings.
6691 """
6701 def value_decode(self, val):
6716 return _unquote( val ), val
6721 def value_encode(self, val):
6732 strval = str(val)
6742 return strval, _quote( strval )
675n/a# end SimpleCookie
676n/a
6772class SerialCookie(BaseCookie):
678n/a """SerialCookie
679n/a SerialCookie supports arbitrary objects as cookie values. All
680n/a values are serialized (using cPickle) before being sent to the
681n/a client. All incoming values are assumed to be valid Pickle
682n/a representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
683n/a FORMAT, THEN AN EXCEPTION WILL BE RAISED.
684n/a
685n/a Note: Large cookie values add overhead because they must be
686n/a retransmitted on every HTTP transaction.
687n/a
688n/a Note: HTTP has a 2k limit on the size of a cookie. This class
689n/a does not check for this limit, so be careful!!!
6901 """
6911 def __init__(self, input=None):
6922 warnings.warn("SerialCookie class is insecure; do not use it",
6932 DeprecationWarning)
6942 BaseCookie.__init__(self, input)
695n/a # end __init__
6961 def value_decode(self, val):
697n/a # This could raise an exception!
6980 return loads( _unquote(val) ), val
6991 def value_encode(self, val):
7002 return val, _quote( dumps(val) )
701n/a# end SerialCookie
702n/a
7032class SmartCookie(BaseCookie):
704n/a """SmartCookie
705n/a SmartCookie supports arbitrary objects as cookie values. If the
706n/a object is a string, then it is quoted. If the object is not a
707n/a string, however, then SmartCookie will use cPickle to serialize
708n/a the object into a string representation.
709n/a
710n/a Note: Large cookie values add overhead because they must be
711n/a retransmitted on every HTTP transaction.
712n/a
713n/a Note: HTTP has a 2k limit on the size of a cookie. This class
714n/a does not check for this limit, so be careful!!!
7151 """
7161 def __init__(self, input=None):
7179 warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
7189 DeprecationWarning)
7199 BaseCookie.__init__(self, input)
720n/a # end __init__
7211 def value_decode(self, val):
7223 strval = _unquote(val)
7233 try:
7243 return loads(strval), val
7253 except:
7263 return strval, val
7271 def value_encode(self, val):
7287 if type(val) == type(""):
7296 return val, _quote(val)
730n/a else:
7311 return val, _quote( dumps(val) )
732n/a# end SmartCookie
733n/a
734n/a
735n/a###########################################################
736n/a# Backwards Compatibility: Don't break any existing code!
737n/a
738n/a# We provide Cookie() as an alias for SmartCookie()
7391Cookie = SmartCookie
740n/a
741n/a#
742n/a###########################################################
743n/a
7441def _test():
7450 import doctest, Cookie
7460 return doctest.testmod(Cookie)
747n/a
7481if __name__ == "__main__":
7490 _test()
750n/a
751n/a
752n/a#Local Variables:
753n/a#tab-width: 4
754n/a#end: