blob: ca559e85b303ef884b73877e6ded27e0caa2a668 [file] [log] [blame]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +00001#!/usr/bin/env python
2#
3
4####
5# Copyright 2000 by Timothy O'Malley <timo@alum.mit.edu>
Tim Peters88869f92001-01-14 23:36:06 +00006#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +00007# All Rights Reserved
Tim Peters88869f92001-01-14 23:36:06 +00008#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +00009# 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
Tim Peters88869f92001-01-14 23:36:06 +000016# prior permission.
17#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000018# 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
Tim Peters88869f92001-01-14 23:36:06 +000025# PERFORMANCE OF THIS SOFTWARE.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000026#
27####
Tim Peters88869f92001-01-14 23:36:06 +000028#
29# Id: Cookie.py,v 2.29 2000/08/23 05:28:49 timo Exp
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000030# 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
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +000037# Dave Mitchell (davem@magnet.com) in 1995, when he released the
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000038# first version of nscookie.py.
39#
40####
41
Guido van Rossum58b6f5b2001-04-06 19:39:11 +000042r"""
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000043Here's a sample session to show how to use this module.
44At the moment, this is the only documentation.
45
46The Basics
47----------
48
49Importing is easy..
50
51 >>> import Cookie
52
53Most of the time you start by creating a cookie. Cookies come in
Andrew M. Kuchling3c76ad02002-12-17 18:56:26 +000054three flavors, each with slightly different encoding semantics, but
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000055more 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
62Cookie.Cookie() to create an Cookie object. Although deprecated, it
63is still supported by the code. See the Backward Compatibility notes
64for more information.]
65
66Once you've created your Cookie, you can add values just as if it were
67a dictionary.
68
69 >>> C = Cookie.SmartCookie()
70 >>> C["fig"] = "newton"
71 >>> C["sugar"] = "wafer"
Georg Brandl532efab2005-08-24 22:34:21 +000072 >>> C.output()
73 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000074
75Notice that the printable representation of a Cookie is the
76appropriate format for a Set-Cookie: header. This is the
77default behavior. You can change the header and printed
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +000078attributes by using the .output() function
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000079
80 >>> C = Cookie.SmartCookie()
81 >>> C["rocky"] = "road"
82 >>> C["rocky"]["path"] = "/cookie"
Guido van Rossumfff80df2007-02-09 20:33:44 +000083 >>> print(C.output(header="Cookie:"))
Georg Brandl532efab2005-08-24 22:34:21 +000084 Cookie: rocky=road; Path=/cookie
Guido van Rossumfff80df2007-02-09 20:33:44 +000085 >>> print(C.output(attrs=[], header="Cookie:"))
Georg Brandl532efab2005-08-24 22:34:21 +000086 Cookie: rocky=road
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000087
88The load() method of a Cookie extracts cookies from a string. In a
89CGI script, you would use this method to extract the cookies from the
90HTTP_COOKIE environment variable.
91
92 >>> C = Cookie.SmartCookie()
93 >>> C.load("chips=ahoy; vienna=finger")
Georg Brandl532efab2005-08-24 22:34:21 +000094 >>> C.output()
95 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000096
97The load() method is darn-tootin smart about identifying cookies
98within a string. Escaped quotation marks, nested semicolons, and other
99such trickeries do not confuse it.
100
101 >>> C = Cookie.SmartCookie()
102 >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
Guido van Rossumfff80df2007-02-09 20:33:44 +0000103 >>> print(C)
Georg Brandl532efab2005-08-24 22:34:21 +0000104 Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000105
106Each element of the Cookie also supports all of the RFC 2109
107Cookie attributes. Here's an example which sets the Path
108attribute.
109
110 >>> C = Cookie.SmartCookie()
111 >>> C["oreo"] = "doublestuff"
112 >>> C["oreo"]["path"] = "/"
Guido van Rossumfff80df2007-02-09 20:33:44 +0000113 >>> print(C)
Georg Brandl532efab2005-08-24 22:34:21 +0000114 Set-Cookie: oreo=doublestuff; Path=/
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000115
116Each dictionary element has a 'value' attribute, which gives you
Tim Peters88869f92001-01-14 23:36:06 +0000117back the value associated with the key.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000118
119 >>> C = Cookie.SmartCookie()
120 >>> C["twix"] = "none for you"
121 >>> C["twix"].value
122 'none for you'
123
124
125A Bit More Advanced
126-------------------
127
128As mentioned before, there are three different flavors of Cookie
129objects, each with different encoding/decoding semantics. This
130section briefly discusses the differences.
131
132SimpleCookie
133
134The SimpleCookie expects that all values should be standard strings.
135Just to be sure, SimpleCookie invokes the str() builtin to convert
136the 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'
Georg Brandl532efab2005-08-24 22:34:21 +0000145 >>> C.output()
146 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000147
Tim Peters88869f92001-01-14 23:36:06 +0000148
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000149SerialCookie
150
151The SerialCookie expects that all values should be serialized using
Guido van Rossum99603b02007-07-20 00:22:32 +0000152pickle. As a result of serializing, SerialCookie can save almost any
153Python object to a value, and recover the exact same object when the
154cookie has been returned. (SerialCookie can yield some
155strange-looking cookie values, however.)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000156
157 >>> C = Cookie.SerialCookie()
158 >>> C["number"] = 7
159 >>> C["string"] = "seven"
160 >>> C["number"].value
161 7
162 >>> C["string"].value
163 'seven'
Guido van Rossum99603b02007-07-20 00:22:32 +0000164 >>> C.output().replace('p0', 'p1') # Hack for pickling differences
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000165 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="Vseven\\012p1\\012."'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000166
167Be warned, however, if SerialCookie cannot de-serialize a value (because
168it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
169
170
171SmartCookie
172
173The SmartCookie combines aspects of each of the other two flavors.
174When setting a value in a dictionary-fashion, the SmartCookie will
Guido van Rossum99603b02007-07-20 00:22:32 +0000175serialize (ala pickle) the value *if and only if* it isn't a
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000176Python string. String objects are *not* serialized. Similarly,
177when the load() method parses out values, it attempts to de-serialize
178the value. If it fails, then it fallsback to treating the value
179as a string.
180
181 >>> C = Cookie.SmartCookie()
182 >>> C["number"] = 7
183 >>> C["string"] = "seven"
184 >>> C["number"].value
185 7
186 >>> C["string"].value
187 'seven'
Georg Brandl532efab2005-08-24 22:34:21 +0000188 >>> C.output()
189 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000190
191
192Backwards Compatibility
193-----------------------
194
195In order to keep compatibilty with earlier versions of Cookie.py,
196it is still possible to use Cookie.Cookie() to create a Cookie. In
197fact, this simply returns a SmartCookie.
198
199 >>> C = Cookie.Cookie()
Guido van Rossumfff80df2007-02-09 20:33:44 +0000200 >>> print(C.__class__.__name__)
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000201 SmartCookie
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000202
203
204Finis.
205""" #"
206# ^
207# |----helps out font-lock
208
209#
210# Import our required modules
Tim Peters88869f92001-01-14 23:36:06 +0000211#
Martin v. Löwis02d893c2001-08-02 07:15:29 +0000212import string
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000213
Guido van Rossum99603b02007-07-20 00:22:32 +0000214from pickle import dumps, loads
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000215
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000216import re, warnings
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000217
Skip Montanaroe99d5ea2001-01-20 19:54:20 +0000218__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
219 "SmartCookie","Cookie"]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000220
Fred Draked451ec12002-04-26 02:29:55 +0000221_nulljoin = ''.join
Georg Brandl532efab2005-08-24 22:34:21 +0000222_semispacejoin = '; '.join
Georg Brandl8246c432005-08-25 07:32:42 +0000223_spacejoin = ' '.join
Fred Draked451ec12002-04-26 02:29:55 +0000224
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000225#
226# Define an exception visible to External modules
227#
228class CookieError(Exception):
229 pass
230
231
232# These quoting routines conform to the RFC2109 specification, which in
233# turn references the character definitions from RFC2068. They provide
234# a two-way quoting algorithm. Any non-text character is translated
235# into a 4 character sequence: a forward-slash followed by the
236# three-digit octal equivalent of the character. Any '\' or '"' is
237# quoted with a preceeding '\' slash.
Tim Peters88869f92001-01-14 23:36:06 +0000238#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000239# These are taken from RFC2068 and RFC2109.
240# _LegalChars is the list of chars which don't require "'s
241# _Translator hash-table for fast quoting
242#
Fred Drake79e75e12001-07-20 19:05:50 +0000243_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000244_Translator = {
245 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
246 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
247 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
248 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
249 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
250 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
251 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
252 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
253 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
254 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
255 '\036' : '\\036', '\037' : '\\037',
256
257 '"' : '\\"', '\\' : '\\\\',
258
259 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
260 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
261 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
262 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
263 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
264 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
265 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
266 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
267 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
268 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
269 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
270 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
271 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
272 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
273 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
274 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
275 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
276 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
277 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
278 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
279 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
280 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
281 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
282 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
283 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
284 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
285 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
286 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
287 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
288 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
289 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
290 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
291 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
292 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
293 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
294 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
295 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
296 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
297 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
298 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
299 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
300 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
301 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
302 }
303
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000304def _quote(str, LegalChars=_LegalChars):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000305 #
306 # If the string does not need to be double-quoted,
307 # then just return the string. Otherwise, surround
308 # the string in doublequotes and precede quote (with a \)
309 # special characters.
310 #
Guido van Rossum0c41e882007-07-03 16:46:40 +0000311 if all(c in LegalChars for c in str):
Fred Drakeff5364a2000-08-24 14:40:35 +0000312 return str
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000313 else:
Fred Draked451ec12002-04-26 02:29:55 +0000314 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000315# end _quote
316
317
318_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
319_QuotePatt = re.compile(r"[\\].")
320
Fred Draked451ec12002-04-26 02:29:55 +0000321def _unquote(str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000322 # If there aren't any doublequotes,
323 # then there can't be any special characters. See RFC 2109.
324 if len(str) < 2:
325 return str
326 if str[0] != '"' or str[-1] != '"':
327 return str
328
329 # We have to assume that we must decode this string.
330 # Down to work.
331
332 # Remove the "s
333 str = str[1:-1]
Fred Drakeff5364a2000-08-24 14:40:35 +0000334
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000335 # Check for special sequences. Examples:
336 # \012 --> \n
337 # \" --> "
338 #
339 i = 0
340 n = len(str)
341 res = []
342 while 0 <= i < n:
343 Omatch = _OctalPatt.search(str, i)
344 Qmatch = _QuotePatt.search(str, i)
345 if not Omatch and not Qmatch: # Neither matched
346 res.append(str[i:])
347 break
348 # else:
349 j = k = -1
350 if Omatch: j = Omatch.start(0)
351 if Qmatch: k = Qmatch.start(0)
352 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
353 res.append(str[i:k])
354 res.append(str[k+1])
355 i = k+2
356 else: # OctalPatt matched
357 res.append(str[i:j])
Fred Draked451ec12002-04-26 02:29:55 +0000358 res.append( chr( int(str[j+1:j+4], 8) ) )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000359 i = j+4
Fred Draked451ec12002-04-26 02:29:55 +0000360 return _nulljoin(res)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000361# end _unquote
362
363# The _getdate() routine is used to set the expiration time in
364# the cookie's HTTP header. By default, _getdate() returns the
Tim Peters88869f92001-01-14 23:36:06 +0000365# current time in the appropriate "expires" format for a
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000366# Set-Cookie header. The one optional argument is an offset from
367# now, in seconds. For example, an offset of -3600 means "one hour ago".
368# The offset may be a floating point number.
369#
370
371_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
372
373_monthname = [None,
374 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
375 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
376
377def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
378 from time import gmtime, time
379 now = time()
380 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
381 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
382 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
383
384
385#
386# A class to hold ONE key,value pair.
387# In a cookie, each such pair may have several attributes.
388# so this class is used to keep the attributes associated
389# with the appropriate key,value pair.
390# This class also includes a coded_value attribute, which
391# is used to hold the network representation of the
392# value. This is most useful when Python objects are
393# pickled for network transit.
394#
395
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000396class Morsel(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000397 # RFC 2109 lists these attributes as reserved:
398 # path comment domain
399 # max-age secure version
Tim Peters88869f92001-01-14 23:36:06 +0000400 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000401 # For historical reasons, these attributes are also reserved:
402 # expires
403 #
404 # This dictionary provides a mapping from the lowercase
405 # variant on the left to the appropriate traditional
406 # formatting on the right.
407 _reserved = { "expires" : "expires",
408 "path" : "Path",
409 "comment" : "Comment",
410 "domain" : "Domain",
411 "max-age" : "Max-Age",
412 "secure" : "secure",
413 "version" : "Version",
414 }
Fred Drakeff5364a2000-08-24 14:40:35 +0000415
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000416 def __init__(self):
417 # Set defaults
418 self.key = self.value = self.coded_value = None
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000419
420 # Set default attributes
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000421 for K in self._reserved:
422 dict.__setitem__(self, K, "")
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000423 # end __init__
424
425 def __setitem__(self, K, V):
Fred Draked451ec12002-04-26 02:29:55 +0000426 K = K.lower()
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000427 if not K in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000428 raise CookieError("Invalid Attribute %s" % K)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000429 dict.__setitem__(self, K, V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000430 # end __setitem__
431
432 def isReservedKey(self, K):
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000433 return K.lower() in self._reserved
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000434 # end isReservedKey
435
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000436 def set(self, key, val, coded_val, LegalChars=_LegalChars):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000437 # First we verify that the key isn't a reserved word
438 # Second we make sure it only contains legal characters
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000439 if key.lower() in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000440 raise CookieError("Attempt to set a reserved key: %s" % key)
Guido van Rossum0c41e882007-07-03 16:46:40 +0000441 if any(c not in LegalChars for c in key):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000442 raise CookieError("Illegal key value: %s" % key)
443
444 # It's a good key, so save it.
445 self.key = key
446 self.value = val
447 self.coded_value = coded_val
448 # end set
449
450 def output(self, attrs=None, header = "Set-Cookie:"):
451 return "%s %s" % ( header, self.OutputString(attrs) )
452
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000453 __str__ = output
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000454
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000455 def __repr__(self):
456 return '<%s: %s=%s>' % (self.__class__.__name__,
457 self.key, repr(self.value) )
Fred Drakeff5364a2000-08-24 14:40:35 +0000458
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000459 def js_output(self, attrs=None):
460 # Print javascript
461 return """
Georg Brandl03a33ea2005-06-26 21:02:49 +0000462 <script type="text/javascript">
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000463 <!-- begin hiding
Georg Brandl03a33ea2005-06-26 21:02:49 +0000464 document.cookie = \"%s\";
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000465 // end hiding -->
466 </script>
467 """ % ( self.OutputString(attrs), )
468 # end js_output()
469
470 def OutputString(self, attrs=None):
471 # Build up our result
472 #
473 result = []
474 RA = result.append
Fred Drakeff5364a2000-08-24 14:40:35 +0000475
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000476 # First, the key=value pair
Georg Brandl532efab2005-08-24 22:34:21 +0000477 RA("%s=%s" % (self.key, self.coded_value))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000478
479 # Now add any defined attributes
Fred Drake8152d322000-12-12 23:20:45 +0000480 if attrs is None:
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000481 attrs = self._reserved
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000482 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000483 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000484 if V == "": continue
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000485 if K not in attrs: continue
486 if K == "expires" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000487 RA("%s=%s" % (self._reserved[K], _getdate(V)))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000488 elif K == "max-age" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000489 RA("%s=%d" % (self._reserved[K], V))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000490 elif K == "secure":
Georg Brandl532efab2005-08-24 22:34:21 +0000491 RA(str(self._reserved[K]))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000492 else:
Georg Brandl532efab2005-08-24 22:34:21 +0000493 RA("%s=%s" % (self._reserved[K], V))
Fred Drakeff5364a2000-08-24 14:40:35 +0000494
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000495 # Return the result
Georg Brandl532efab2005-08-24 22:34:21 +0000496 return _semispacejoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000497 # end OutputString
498# end Morsel class
499
500
501
502#
503# Pattern for finding cookie
504#
505# This used to be strict parsing based on the RFC2109 and RFC2068
506# specifications. I have since discovered that MSIE 3.0x doesn't
507# follow the character rules outlined in those specs. As a
508# result, the parsing rules here are less strict.
509#
510
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000511_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000512_CookiePattern = re.compile(
513 r"(?x)" # This is a Verbose pattern
514 r"(?P<key>" # Start of group 'key'
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000515 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000516 r")" # End of group 'key'
517 r"\s*=\s*" # Equal Sign
518 r"(?P<val>" # Start of group 'val'
519 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
520 r"|" # or
521 ""+ _LegalCharsPatt +"*" # Any word or empty string
522 r")" # End of group 'val'
523 r"\s*;?" # Probably ending in a semi-colon
524 )
525
526
527# At long last, here is the cookie class.
528# Using this class is almost just like using a dictionary.
529# See this module's docstring for example usage.
530#
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000531class BaseCookie(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000532 # A container class for a set of Morsels
533 #
Fred Drakeff5364a2000-08-24 14:40:35 +0000534
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000535 def value_decode(self, val):
536 """real_value, coded_value = value_decode(STRING)
537 Called prior to setting a cookie's value from the network
538 representation. The VALUE is the value read from HTTP
539 header.
540 Override this function to modify the behavior of cookies.
541 """
542 return val, val
543 # end value_encode
544
545 def value_encode(self, val):
546 """real_value, coded_value = value_encode(VALUE)
547 Called prior to setting a cookie's value from the dictionary
548 representation. The VALUE is the value being assigned.
549 Override this function to modify the behavior of cookies.
550 """
551 strval = str(val)
552 return strval, strval
553 # end value_encode
Fred Drakeff5364a2000-08-24 14:40:35 +0000554
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000555 def __init__(self, input=None):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000556 if input: self.load(input)
557 # end __init__
558
559 def __set(self, key, real_value, coded_value):
560 """Private method for setting a cookie's value"""
561 M = self.get(key, Morsel())
562 M.set(key, real_value, coded_value)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000563 dict.__setitem__(self, key, M)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000564 # end __set
565
566 def __setitem__(self, key, value):
567 """Dictionary style assignment."""
568 rval, cval = self.value_encode(value)
569 self.__set(key, rval, cval)
570 # end __setitem__
571
Georg Brandl532efab2005-08-24 22:34:21 +0000572 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000573 """Return a string suitable for HTTP."""
574 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000575 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000576 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000577 result.append( V.output(attrs, header) )
Fred Draked451ec12002-04-26 02:29:55 +0000578 return sep.join(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000579 # end output
580
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000581 __str__ = output
582
583 def __repr__(self):
584 L = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000585 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000586 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000587 L.append( '%s=%s' % (K,repr(V.value) ) )
Georg Brandl8246c432005-08-25 07:32:42 +0000588 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
Fred Drakeff5364a2000-08-24 14:40:35 +0000589
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000590 def js_output(self, attrs=None):
591 """Return a string suitable for JavaScript."""
592 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000593 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000594 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000595 result.append( V.js_output(attrs) )
Fred Draked451ec12002-04-26 02:29:55 +0000596 return _nulljoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000597 # end js_output
598
599 def load(self, rawdata):
600 """Load cookies from a string (presumably HTTP_COOKIE) or
601 from a dictionary. Loading cookies from a dictionary 'd'
602 is equivalent to calling:
603 map(Cookie.__setitem__, d.keys(), d.values())
604 """
605 if type(rawdata) == type(""):
606 self.__ParseString(rawdata)
607 else:
608 self.update(rawdata)
609 return
610 # end load()
Fred Drakeff5364a2000-08-24 14:40:35 +0000611
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000612 def __ParseString(self, str, patt=_CookiePattern):
613 i = 0 # Our starting point
614 n = len(str) # Length of string
615 M = None # current morsel
616
617 while 0 <= i < n:
618 # Start looking for a cookie
619 match = patt.search(str, i)
620 if not match: break # No more cookies
621
622 K,V = match.group("key"), match.group("val")
623 i = match.end(0)
624
625 # Parse the key, value in case it's metainfo
626 if K[0] == "$":
627 # We ignore attributes which pertain to the cookie
628 # mechanism as a whole. See RFC 2109.
629 # (Does anyone care?)
630 if M:
631 M[ K[1:] ] = V
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000632 elif K.lower() in Morsel._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000633 if M:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000634 M[ K ] = _unquote(V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000635 else:
636 rval, cval = self.value_decode(V)
637 self.__set(K, rval, cval)
638 M = self[K]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000639 # end __ParseString
640# end BaseCookie class
641
642class SimpleCookie(BaseCookie):
643 """SimpleCookie
644 SimpleCookie supports strings as cookie values. When setting
645 the value using the dictionary assignment notation, SimpleCookie
646 calls the builtin str() to convert the value to a string. Values
647 received from HTTP are kept as strings.
648 """
649 def value_decode(self, val):
650 return _unquote( val ), val
651 def value_encode(self, val):
652 strval = str(val)
653 return strval, _quote( strval )
654# end SimpleCookie
655
656class SerialCookie(BaseCookie):
657 """SerialCookie
658 SerialCookie supports arbitrary objects as cookie values. All
Guido van Rossum99603b02007-07-20 00:22:32 +0000659 values are serialized (using pickle) before being sent to the
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000660 client. All incoming values are assumed to be valid Pickle
661 representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
662 FORMAT, THEN AN EXCEPTION WILL BE RAISED.
663
664 Note: Large cookie values add overhead because they must be
665 retransmitted on every HTTP transaction.
Fred Drakeff5364a2000-08-24 14:40:35 +0000666
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000667 Note: HTTP has a 2k limit on the size of a cookie. This class
668 does not check for this limit, so be careful!!!
669 """
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000670 def __init__(self, input=None):
671 warnings.warn("SerialCookie class is insecure; do not use it",
672 DeprecationWarning)
673 BaseCookie.__init__(self, input)
674 # end __init__
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000675 def value_decode(self, val):
676 # This could raise an exception!
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000677 return loads( _unquote(val).encode('latin-1') ), val
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000678 def value_encode(self, val):
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000679 return val, _quote( dumps(val).decode('latin-1') )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000680# end SerialCookie
681
682class SmartCookie(BaseCookie):
683 """SmartCookie
684 SmartCookie supports arbitrary objects as cookie values. If the
685 object is a string, then it is quoted. If the object is not a
Guido van Rossum99603b02007-07-20 00:22:32 +0000686 string, however, then SmartCookie will use pickle to serialize
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000687 the object into a string representation.
688
689 Note: Large cookie values add overhead because they must be
690 retransmitted on every HTTP transaction.
Fred Drakeff5364a2000-08-24 14:40:35 +0000691
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000692 Note: HTTP has a 2k limit on the size of a cookie. This class
693 does not check for this limit, so be careful!!!
694 """
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000695 def __init__(self, input=None):
696 warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
697 DeprecationWarning)
698 BaseCookie.__init__(self, input)
699 # end __init__
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000700 def value_decode(self, val):
701 strval = _unquote(val)
702 try:
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000703 return loads(strval.encode('latin-1')), val
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000704 except:
705 return strval, val
706 def value_encode(self, val):
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000707 if isinstance(val, str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000708 return val, _quote(val)
709 else:
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000710 return val, _quote( dumps(val).decode('latin-1') )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000711# end SmartCookie
712
713
714###########################################################
715# Backwards Compatibility: Don't break any existing code!
716
717# We provide Cookie() as an alias for SmartCookie()
718Cookie = SmartCookie
719
720#
721###########################################################
722
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000723def _test():
724 import doctest, Cookie
725 return doctest.testmod(Cookie)
726
727if __name__ == "__main__":
728 _test()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000729
730
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000731#Local Variables:
732#tab-width: 4
733#end: