blob: d67443745721a7d78222983e615dae2c4f13fac1 [file] [log] [blame]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +00001####
2# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
Tim Peters88869f92001-01-14 23:36:06 +00003#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +00004# All Rights Reserved
Tim Peters88869f92001-01-14 23:36:06 +00005#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +00006# Permission to use, copy, modify, and distribute this software
7# and its documentation for any purpose and without fee is hereby
8# granted, provided that the above copyright notice appear in all
9# copies and that both that copyright notice and this permission
10# notice appear in supporting documentation, and that the name of
11# Timothy O'Malley not be used in advertising or publicity
12# pertaining to distribution of the software without specific, written
Tim Peters88869f92001-01-14 23:36:06 +000013# prior permission.
14#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000015# Timothy O'Malley DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16# SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
17# AND FITNESS, IN NO EVENT SHALL Timothy O'Malley BE LIABLE FOR
18# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
Tim Peters88869f92001-01-14 23:36:06 +000022# PERFORMANCE OF THIS SOFTWARE.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000023#
24####
Tim Peters88869f92001-01-14 23:36:06 +000025#
26# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000027# by Timothy O'Malley <timo@alum.mit.edu>
28#
29# Cookie.py is a Python module for the handling of HTTP
30# cookies as a Python dictionary. See RFC 2109 for more
31# information on cookies.
32#
33# The original idea to treat Cookies as a dictionary came from
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +000034# Dave Mitchell (davem@magnet.com) in 1995, when he released the
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000035# first version of nscookie.py.
36#
37####
38
Guido van Rossum58b6f5b2001-04-06 19:39:11 +000039r"""
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000040Here's a sample session to show how to use this module.
41At the moment, this is the only documentation.
42
43The Basics
44----------
45
46Importing is easy..
47
48 >>> import Cookie
49
50Most of the time you start by creating a cookie. Cookies come in
Andrew M. Kuchling3c76ad02002-12-17 18:56:26 +000051three flavors, each with slightly different encoding semantics, but
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000052more on that later.
53
54 >>> C = Cookie.SimpleCookie()
55 >>> C = Cookie.SerialCookie()
56 >>> C = Cookie.SmartCookie()
57
58[Note: Long-time users of Cookie.py will remember using
Ezio Melottif97376f2014-07-09 15:45:25 +030059Cookie.Cookie() to create a Cookie object. Although deprecated, it
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000060is still supported by the code. See the Backward Compatibility notes
61for more information.]
62
63Once you've created your Cookie, you can add values just as if it were
64a dictionary.
65
66 >>> C = Cookie.SmartCookie()
67 >>> C["fig"] = "newton"
68 >>> C["sugar"] = "wafer"
Georg Brandl532efab2005-08-24 22:34:21 +000069 >>> C.output()
70 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000071
72Notice that the printable representation of a Cookie is the
73appropriate format for a Set-Cookie: header. This is the
74default behavior. You can change the header and printed
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +000075attributes by using the .output() function
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000076
77 >>> C = Cookie.SmartCookie()
78 >>> C["rocky"] = "road"
79 >>> C["rocky"]["path"] = "/cookie"
80 >>> print C.output(header="Cookie:")
Georg Brandl532efab2005-08-24 22:34:21 +000081 Cookie: rocky=road; Path=/cookie
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000082 >>> print C.output(attrs=[], header="Cookie:")
Georg Brandl532efab2005-08-24 22:34:21 +000083 Cookie: rocky=road
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000084
85The load() method of a Cookie extracts cookies from a string. In a
86CGI script, you would use this method to extract the cookies from the
87HTTP_COOKIE environment variable.
88
89 >>> C = Cookie.SmartCookie()
90 >>> C.load("chips=ahoy; vienna=finger")
Georg Brandl532efab2005-08-24 22:34:21 +000091 >>> C.output()
92 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000093
94The load() method is darn-tootin smart about identifying cookies
95within a string. Escaped quotation marks, nested semicolons, and other
96such trickeries do not confuse it.
97
98 >>> C = Cookie.SmartCookie()
99 >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000100 >>> print C
Georg Brandl532efab2005-08-24 22:34:21 +0000101 Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000102
103Each element of the Cookie also supports all of the RFC 2109
104Cookie attributes. Here's an example which sets the Path
105attribute.
106
107 >>> C = Cookie.SmartCookie()
108 >>> C["oreo"] = "doublestuff"
109 >>> C["oreo"]["path"] = "/"
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000110 >>> print C
Georg Brandl532efab2005-08-24 22:34:21 +0000111 Set-Cookie: oreo=doublestuff; Path=/
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000112
113Each dictionary element has a 'value' attribute, which gives you
Tim Peters88869f92001-01-14 23:36:06 +0000114back the value associated with the key.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000115
116 >>> C = Cookie.SmartCookie()
117 >>> C["twix"] = "none for you"
118 >>> C["twix"].value
119 'none for you'
120
121
122A Bit More Advanced
123-------------------
124
125As mentioned before, there are three different flavors of Cookie
126objects, each with different encoding/decoding semantics. This
127section briefly discusses the differences.
128
129SimpleCookie
130
131The SimpleCookie expects that all values should be standard strings.
132Just to be sure, SimpleCookie invokes the str() builtin to convert
133the value to a string, when the values are set dictionary-style.
134
135 >>> C = Cookie.SimpleCookie()
136 >>> C["number"] = 7
137 >>> C["string"] = "seven"
138 >>> C["number"].value
139 '7'
140 >>> C["string"].value
141 'seven'
Georg Brandl532efab2005-08-24 22:34:21 +0000142 >>> C.output()
143 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000144
Tim Peters88869f92001-01-14 23:36:06 +0000145
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000146SerialCookie
147
148The SerialCookie expects that all values should be serialized using
149cPickle (or pickle, if cPickle isn't available). As a result of
150serializing, SerialCookie can save almost any Python object to a
151value, and recover the exact same object when the cookie has been
152returned. (SerialCookie can yield some strange-looking cookie
153values, however.)
154
155 >>> C = Cookie.SerialCookie()
156 >>> C["number"] = 7
157 >>> C["string"] = "seven"
158 >>> C["number"].value
159 7
160 >>> C["string"].value
161 'seven'
Georg Brandl532efab2005-08-24 22:34:21 +0000162 >>> C.output()
163 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000164
165Be warned, however, if SerialCookie cannot de-serialize a value (because
166it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
167
168
169SmartCookie
170
171The SmartCookie combines aspects of each of the other two flavors.
172When setting a value in a dictionary-fashion, the SmartCookie will
173serialize (ala cPickle) the value *if and only if* it isn't a
174Python string. String objects are *not* serialized. Similarly,
175when the load() method parses out values, it attempts to de-serialize
176the value. If it fails, then it fallsback to treating the value
177as a string.
178
179 >>> C = Cookie.SmartCookie()
180 >>> C["number"] = 7
181 >>> C["string"] = "seven"
182 >>> C["number"].value
183 7
184 >>> C["string"].value
185 'seven'
Georg Brandl532efab2005-08-24 22:34:21 +0000186 >>> C.output()
187 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000188
189
190Backwards Compatibility
191-----------------------
192
193In order to keep compatibilty with earlier versions of Cookie.py,
194it is still possible to use Cookie.Cookie() to create a Cookie. In
195fact, this simply returns a SmartCookie.
196
197 >>> C = Cookie.Cookie()
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000198 >>> print C.__class__.__name__
199 SmartCookie
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000200
201
202Finis.
203""" #"
204# ^
205# |----helps out font-lock
206
207#
208# Import our required modules
Tim Peters88869f92001-01-14 23:36:06 +0000209#
Martin v. Löwis02d893c2001-08-02 07:15:29 +0000210import string
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000211
212try:
213 from cPickle import dumps, loads
214except ImportError:
215 from pickle import dumps, loads
216
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000217import re, warnings
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000218
Skip Montanaroe99d5ea2001-01-20 19:54:20 +0000219__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
220 "SmartCookie","Cookie"]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000221
Fred Draked451ec12002-04-26 02:29:55 +0000222_nulljoin = ''.join
Georg Brandl532efab2005-08-24 22:34:21 +0000223_semispacejoin = '; '.join
Georg Brandl8246c432005-08-25 07:32:42 +0000224_spacejoin = ' '.join
Fred Draked451ec12002-04-26 02:29:55 +0000225
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000226#
227# Define an exception visible to External modules
228#
229class CookieError(Exception):
230 pass
231
232
233# These quoting routines conform to the RFC2109 specification, which in
234# turn references the character definitions from RFC2068. They provide
235# a two-way quoting algorithm. Any non-text character is translated
236# into a 4 character sequence: a forward-slash followed by the
237# three-digit octal equivalent of the character. Any '\' or '"' is
Ezio Melottif5469cf2013-08-17 15:43:51 +0300238# quoted with a preceding '\' slash.
Tim Peters88869f92001-01-14 23:36:06 +0000239#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000240# These are taken from RFC2068 and RFC2109.
241# _LegalChars is the list of chars which don't require "'s
242# _Translator hash-table for fast quoting
243#
Fred Drake79e75e12001-07-20 19:05:50 +0000244_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000245_Translator = {
246 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
247 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
248 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
249 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
250 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
251 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
252 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
253 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
254 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
255 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
256 '\036' : '\\036', '\037' : '\\037',
257
R. David Murray08fc7012010-12-28 19:11:03 +0000258 # Because of the way browsers really handle cookies (as opposed
259 # to what the RFC says) we also encode , and ;
260
261 ',' : '\\054', ';' : '\\073',
262
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000263 '"' : '\\"', '\\' : '\\\\',
264
265 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
266 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
267 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
268 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
269 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
270 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
271 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
272 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
273 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
274 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
275 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
276 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
277 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
278 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
279 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
280 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
281 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
282 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
283 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
284 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
285 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
286 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
287 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
288 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
289 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
290 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
291 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
292 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
293 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
294 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
295 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
296 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
297 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
298 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
299 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
300 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
301 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
302 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
303 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
304 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
305 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
306 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
307 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
308 }
Tim Petersc02c1c82006-08-15 00:25:04 +0000309
Georg Brandld76bd692006-08-14 22:01:24 +0000310_idmap = ''.join(chr(x) for x in xrange(256))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000311
312def _quote(str, LegalChars=_LegalChars,
Georg Brandld76bd692006-08-14 22:01:24 +0000313 idmap=_idmap, translate=string.translate):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000314 #
315 # If the string does not need to be double-quoted,
316 # then just return the string. Otherwise, surround
317 # the string in doublequotes and precede quote (with a \)
318 # special characters.
319 #
320 if "" == translate(str, idmap, LegalChars):
Fred Drakeff5364a2000-08-24 14:40:35 +0000321 return str
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000322 else:
Fred Draked451ec12002-04-26 02:29:55 +0000323 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000324# end _quote
325
326
327_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
328_QuotePatt = re.compile(r"[\\].")
329
Fred Draked451ec12002-04-26 02:29:55 +0000330def _unquote(str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000331 # If there aren't any doublequotes,
332 # then there can't be any special characters. See RFC 2109.
333 if len(str) < 2:
334 return str
335 if str[0] != '"' or str[-1] != '"':
336 return str
337
338 # We have to assume that we must decode this string.
339 # Down to work.
340
341 # Remove the "s
342 str = str[1:-1]
Fred Drakeff5364a2000-08-24 14:40:35 +0000343
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000344 # Check for special sequences. Examples:
345 # \012 --> \n
346 # \" --> "
347 #
348 i = 0
349 n = len(str)
350 res = []
351 while 0 <= i < n:
352 Omatch = _OctalPatt.search(str, i)
353 Qmatch = _QuotePatt.search(str, i)
354 if not Omatch and not Qmatch: # Neither matched
355 res.append(str[i:])
356 break
357 # else:
358 j = k = -1
359 if Omatch: j = Omatch.start(0)
360 if Qmatch: k = Qmatch.start(0)
361 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
362 res.append(str[i:k])
363 res.append(str[k+1])
364 i = k+2
365 else: # OctalPatt matched
366 res.append(str[i:j])
Fred Draked451ec12002-04-26 02:29:55 +0000367 res.append( chr( int(str[j+1:j+4], 8) ) )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000368 i = j+4
Fred Draked451ec12002-04-26 02:29:55 +0000369 return _nulljoin(res)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000370# end _unquote
371
372# The _getdate() routine is used to set the expiration time in
373# the cookie's HTTP header. By default, _getdate() returns the
Tim Peters88869f92001-01-14 23:36:06 +0000374# current time in the appropriate "expires" format for a
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000375# Set-Cookie header. The one optional argument is an offset from
376# now, in seconds. For example, an offset of -3600 means "one hour ago".
377# The offset may be a floating point number.
378#
379
380_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
381
382_monthname = [None,
383 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
384 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
385
386def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
387 from time import gmtime, time
388 now = time()
389 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
Senthil Kumaranf439a362012-05-20 12:02:44 +0800390 return "%s, %02d %3s %4d %02d:%02d:%02d GMT" % \
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000391 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
392
393
394#
395# A class to hold ONE key,value pair.
396# In a cookie, each such pair may have several attributes.
397# so this class is used to keep the attributes associated
398# with the appropriate key,value pair.
399# This class also includes a coded_value attribute, which
400# is used to hold the network representation of the
401# value. This is most useful when Python objects are
402# pickled for network transit.
403#
404
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000405class Morsel(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000406 # RFC 2109 lists these attributes as reserved:
407 # path comment domain
408 # max-age secure version
Tim Peters88869f92001-01-14 23:36:06 +0000409 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000410 # For historical reasons, these attributes are also reserved:
411 # expires
412 #
Benjamin Peterson6ac7d7c2008-09-06 19:28:11 +0000413 # This is an extension from Microsoft:
414 # httponly
415 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000416 # This dictionary provides a mapping from the lowercase
417 # variant on the left to the appropriate traditional
418 # formatting on the right.
419 _reserved = { "expires" : "expires",
420 "path" : "Path",
421 "comment" : "Comment",
422 "domain" : "Domain",
423 "max-age" : "Max-Age",
424 "secure" : "secure",
Benjamin Peterson6ac7d7c2008-09-06 19:28:11 +0000425 "httponly" : "httponly",
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000426 "version" : "Version",
427 }
Fred Drakeff5364a2000-08-24 14:40:35 +0000428
Berker Peksagcf0a7062014-07-02 10:48:27 +0300429 _flags = {'secure', 'httponly'}
430
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000431 def __init__(self):
432 # Set defaults
433 self.key = self.value = self.coded_value = None
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000434
435 # Set default attributes
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000436 for K in self._reserved:
437 dict.__setitem__(self, K, "")
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000438 # end __init__
439
440 def __setitem__(self, K, V):
Fred Draked451ec12002-04-26 02:29:55 +0000441 K = K.lower()
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000442 if not K in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000443 raise CookieError("Invalid Attribute %s" % K)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000444 dict.__setitem__(self, K, V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000445 # end __setitem__
446
447 def isReservedKey(self, K):
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000448 return K.lower() in self._reserved
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000449 # end isReservedKey
450
451 def set(self, key, val, coded_val,
452 LegalChars=_LegalChars,
Georg Brandld76bd692006-08-14 22:01:24 +0000453 idmap=_idmap, translate=string.translate):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000454 # First we verify that the key isn't a reserved word
455 # Second we make sure it only contains legal characters
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000456 if key.lower() in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000457 raise CookieError("Attempt to set a reserved key: %s" % key)
458 if "" != translate(key, idmap, LegalChars):
459 raise CookieError("Illegal key value: %s" % key)
460
461 # It's a good key, so save it.
462 self.key = key
463 self.value = val
464 self.coded_value = coded_val
465 # end set
466
467 def output(self, attrs=None, header = "Set-Cookie:"):
468 return "%s %s" % ( header, self.OutputString(attrs) )
469
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000470 __str__ = output
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000471
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000472 def __repr__(self):
473 return '<%s: %s=%s>' % (self.__class__.__name__,
474 self.key, repr(self.value) )
Fred Drakeff5364a2000-08-24 14:40:35 +0000475
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000476 def js_output(self, attrs=None):
477 # Print javascript
478 return """
Georg Brandl03a33ea2005-06-26 21:02:49 +0000479 <script type="text/javascript">
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000480 <!-- begin hiding
Georg Brandl03a33ea2005-06-26 21:02:49 +0000481 document.cookie = \"%s\";
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000482 // end hiding -->
483 </script>
Senthil Kumaranc730a6a2009-04-02 03:00:34 +0000484 """ % ( self.OutputString(attrs).replace('"',r'\"'), )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000485 # end js_output()
486
487 def OutputString(self, attrs=None):
488 # Build up our result
489 #
490 result = []
491 RA = result.append
Fred Drakeff5364a2000-08-24 14:40:35 +0000492
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000493 # First, the key=value pair
Georg Brandl532efab2005-08-24 22:34:21 +0000494 RA("%s=%s" % (self.key, self.coded_value))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000495
496 # Now add any defined attributes
Fred Drake8152d322000-12-12 23:20:45 +0000497 if attrs is None:
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000498 attrs = self._reserved
Tim Peters2f228e72001-05-13 00:19:31 +0000499 items = self.items()
500 items.sort()
501 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000502 if V == "": continue
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000503 if K not in attrs: continue
504 if K == "expires" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000505 RA("%s=%s" % (self._reserved[K], _getdate(V)))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000506 elif K == "max-age" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000507 RA("%s=%d" % (self._reserved[K], V))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000508 elif K == "secure":
Georg Brandl532efab2005-08-24 22:34:21 +0000509 RA(str(self._reserved[K]))
Benjamin Peterson6ac7d7c2008-09-06 19:28:11 +0000510 elif K == "httponly":
511 RA(str(self._reserved[K]))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000512 else:
Georg Brandl532efab2005-08-24 22:34:21 +0000513 RA("%s=%s" % (self._reserved[K], V))
Fred Drakeff5364a2000-08-24 14:40:35 +0000514
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000515 # Return the result
Georg Brandl532efab2005-08-24 22:34:21 +0000516 return _semispacejoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000517 # end OutputString
518# end Morsel class
519
520
521
522#
523# Pattern for finding cookie
524#
525# This used to be strict parsing based on the RFC2109 and RFC2068
526# specifications. I have since discovered that MSIE 3.0x doesn't
527# follow the character rules outlined in those specs. As a
528# result, the parsing rules here are less strict.
529#
530
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000531_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000532_CookiePattern = re.compile(
533 r"(?x)" # This is a Verbose pattern
Guido van Rossumc9cdd0c2014-09-16 15:45:36 -0700534 r"\s*" # Optional whitespace at start of cookie
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000535 r"(?P<key>" # Start of group 'key'
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000536 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000537 r")" # End of group 'key'
Berker Peksagcf0a7062014-07-02 10:48:27 +0300538 r"(" # Optional group: there may not be a value.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000539 r"\s*=\s*" # Equal Sign
540 r"(?P<val>" # Start of group 'val'
541 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
542 r"|" # or
Senthil Kumaran9cffd882012-05-20 16:56:24 +0800543 r"\w{3},\s[\s\w\d-]{9,11}\s[\d:]{8}\sGMT" # Special case for "expires" attr
Georg Brandl78e69572010-08-01 18:52:52 +0000544 r"|" # or
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000545 ""+ _LegalCharsPatt +"*" # Any word or empty string
546 r")" # End of group 'val'
Berker Peksagcf0a7062014-07-02 10:48:27 +0300547 r")?" # End of optional value group
548 r"\s*" # Any number of spaces.
549 r"(\s+|;|$)" # Ending either at space, semicolon, or EOS.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000550 )
551
552
553# At long last, here is the cookie class.
554# Using this class is almost just like using a dictionary.
555# See this module's docstring for example usage.
556#
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000557class BaseCookie(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000558 # A container class for a set of Morsels
559 #
Fred Drakeff5364a2000-08-24 14:40:35 +0000560
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000561 def value_decode(self, val):
562 """real_value, coded_value = value_decode(STRING)
563 Called prior to setting a cookie's value from the network
564 representation. The VALUE is the value read from HTTP
565 header.
566 Override this function to modify the behavior of cookies.
567 """
568 return val, val
569 # end value_encode
570
571 def value_encode(self, val):
572 """real_value, coded_value = value_encode(VALUE)
573 Called prior to setting a cookie's value from the dictionary
574 representation. The VALUE is the value being assigned.
575 Override this function to modify the behavior of cookies.
576 """
577 strval = str(val)
578 return strval, strval
579 # end value_encode
Fred Drakeff5364a2000-08-24 14:40:35 +0000580
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000581 def __init__(self, input=None):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000582 if input: self.load(input)
583 # end __init__
584
585 def __set(self, key, real_value, coded_value):
586 """Private method for setting a cookie's value"""
587 M = self.get(key, Morsel())
588 M.set(key, real_value, coded_value)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000589 dict.__setitem__(self, key, M)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000590 # end __set
591
592 def __setitem__(self, key, value):
593 """Dictionary style assignment."""
594 rval, cval = self.value_encode(value)
595 self.__set(key, rval, cval)
596 # end __setitem__
597
Georg Brandl532efab2005-08-24 22:34:21 +0000598 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000599 """Return a string suitable for HTTP."""
600 result = []
Tim Peters2f228e72001-05-13 00:19:31 +0000601 items = self.items()
602 items.sort()
603 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000604 result.append( V.output(attrs, header) )
Fred Draked451ec12002-04-26 02:29:55 +0000605 return sep.join(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000606 # end output
607
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000608 __str__ = output
609
610 def __repr__(self):
611 L = []
Tim Peters2f228e72001-05-13 00:19:31 +0000612 items = self.items()
613 items.sort()
614 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000615 L.append( '%s=%s' % (K,repr(V.value) ) )
Georg Brandl8246c432005-08-25 07:32:42 +0000616 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
Fred Drakeff5364a2000-08-24 14:40:35 +0000617
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000618 def js_output(self, attrs=None):
619 """Return a string suitable for JavaScript."""
620 result = []
Tim Peters2f228e72001-05-13 00:19:31 +0000621 items = self.items()
622 items.sort()
623 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000624 result.append( V.js_output(attrs) )
Fred Draked451ec12002-04-26 02:29:55 +0000625 return _nulljoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000626 # end js_output
627
628 def load(self, rawdata):
629 """Load cookies from a string (presumably HTTP_COOKIE) or
630 from a dictionary. Loading cookies from a dictionary 'd'
631 is equivalent to calling:
632 map(Cookie.__setitem__, d.keys(), d.values())
633 """
634 if type(rawdata) == type(""):
635 self.__ParseString(rawdata)
636 else:
Georg Brandld22b9512009-09-04 08:17:04 +0000637 # self.update() wouldn't call our custom __setitem__
638 for k, v in rawdata.items():
639 self[k] = v
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000640 return
641 # end load()
Fred Drakeff5364a2000-08-24 14:40:35 +0000642
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000643 def __ParseString(self, str, patt=_CookiePattern):
644 i = 0 # Our starting point
645 n = len(str) # Length of string
646 M = None # current morsel
647
648 while 0 <= i < n:
649 # Start looking for a cookie
Guido van Rossumc9cdd0c2014-09-16 15:45:36 -0700650 match = patt.match(str, i)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000651 if not match: break # No more cookies
652
653 K,V = match.group("key"), match.group("val")
654 i = match.end(0)
655
656 # Parse the key, value in case it's metainfo
657 if K[0] == "$":
658 # We ignore attributes which pertain to the cookie
659 # mechanism as a whole. See RFC 2109.
660 # (Does anyone care?)
661 if M:
662 M[ K[1:] ] = V
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000663 elif K.lower() in Morsel._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000664 if M:
Berker Peksagcf0a7062014-07-02 10:48:27 +0300665 if V is None:
666 if K.lower() in Morsel._flags:
667 M[K] = True
668 else:
669 M[K] = _unquote(V)
670 elif V is not None:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000671 rval, cval = self.value_decode(V)
672 self.__set(K, rval, cval)
673 M = self[K]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000674 # end __ParseString
675# end BaseCookie class
676
677class SimpleCookie(BaseCookie):
678 """SimpleCookie
679 SimpleCookie supports strings as cookie values. When setting
680 the value using the dictionary assignment notation, SimpleCookie
681 calls the builtin str() to convert the value to a string. Values
682 received from HTTP are kept as strings.
683 """
684 def value_decode(self, val):
685 return _unquote( val ), val
686 def value_encode(self, val):
687 strval = str(val)
688 return strval, _quote( strval )
689# end SimpleCookie
690
691class SerialCookie(BaseCookie):
692 """SerialCookie
693 SerialCookie supports arbitrary objects as cookie values. All
694 values are serialized (using cPickle) before being sent to the
695 client. All incoming values are assumed to be valid Pickle
696 representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
697 FORMAT, THEN AN EXCEPTION WILL BE RAISED.
698
699 Note: Large cookie values add overhead because they must be
700 retransmitted on every HTTP transaction.
Fred Drakeff5364a2000-08-24 14:40:35 +0000701
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000702 Note: HTTP has a 2k limit on the size of a cookie. This class
703 does not check for this limit, so be careful!!!
704 """
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000705 def __init__(self, input=None):
706 warnings.warn("SerialCookie class is insecure; do not use it",
707 DeprecationWarning)
708 BaseCookie.__init__(self, input)
709 # end __init__
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000710 def value_decode(self, val):
711 # This could raise an exception!
712 return loads( _unquote(val) ), val
713 def value_encode(self, val):
714 return val, _quote( dumps(val) )
715# end SerialCookie
716
717class SmartCookie(BaseCookie):
718 """SmartCookie
719 SmartCookie supports arbitrary objects as cookie values. If the
720 object is a string, then it is quoted. If the object is not a
721 string, however, then SmartCookie will use cPickle to serialize
722 the object into a string representation.
723
724 Note: Large cookie values add overhead because they must be
725 retransmitted on every HTTP transaction.
Fred Drakeff5364a2000-08-24 14:40:35 +0000726
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000727 Note: HTTP has a 2k limit on the size of a cookie. This class
728 does not check for this limit, so be careful!!!
729 """
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000730 def __init__(self, input=None):
731 warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
732 DeprecationWarning)
733 BaseCookie.__init__(self, input)
734 # end __init__
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000735 def value_decode(self, val):
736 strval = _unquote(val)
737 try:
738 return loads(strval), val
739 except:
740 return strval, val
741 def value_encode(self, val):
742 if type(val) == type(""):
743 return val, _quote(val)
744 else:
745 return val, _quote( dumps(val) )
746# end SmartCookie
747
748
749###########################################################
750# Backwards Compatibility: Don't break any existing code!
751
752# We provide Cookie() as an alias for SmartCookie()
753Cookie = SmartCookie
754
755#
756###########################################################
757
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000758def _test():
759 import doctest, Cookie
760 return doctest.testmod(Cookie)
761
762if __name__ == "__main__":
763 _test()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000764
765
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000766#Local Variables:
767#tab-width: 4
768#end: