blob: 0cd32445e5fb2d5b4f0b965b2d5c5f2fbe2a6392 [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
152cPickle (or pickle, if cPickle isn't available). As a result of
153serializing, SerialCookie can save almost any Python object to a
154value, and recover the exact same object when the cookie has been
155returned. (SerialCookie can yield some strange-looking cookie
156values, however.)
157
158 >>> C = Cookie.SerialCookie()
159 >>> C["number"] = 7
160 >>> C["string"] = "seven"
161 >>> C["number"].value
162 7
163 >>> C["string"].value
164 'seven'
Guido van Rossumbf12cdb2006-08-17 20:24:18 +0000165 >>> C.output().replace('p0', 'p1') # Hack for cPickle/pickle differences
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000166 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="Vseven\\012p1\\012."'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000167
168Be warned, however, if SerialCookie cannot de-serialize a value (because
169it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
170
171
172SmartCookie
173
174The SmartCookie combines aspects of each of the other two flavors.
175When setting a value in a dictionary-fashion, the SmartCookie will
176serialize (ala cPickle) the value *if and only if* it isn't a
177Python string. String objects are *not* serialized. Similarly,
178when the load() method parses out values, it attempts to de-serialize
179the value. If it fails, then it fallsback to treating the value
180as a string.
181
182 >>> C = Cookie.SmartCookie()
183 >>> C["number"] = 7
184 >>> C["string"] = "seven"
185 >>> C["number"].value
186 7
187 >>> C["string"].value
188 'seven'
Georg Brandl532efab2005-08-24 22:34:21 +0000189 >>> C.output()
190 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000191
192
193Backwards Compatibility
194-----------------------
195
196In order to keep compatibilty with earlier versions of Cookie.py,
197it is still possible to use Cookie.Cookie() to create a Cookie. In
198fact, this simply returns a SmartCookie.
199
200 >>> C = Cookie.Cookie()
Guido van Rossumfff80df2007-02-09 20:33:44 +0000201 >>> print(C.__class__.__name__)
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000202 SmartCookie
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000203
204
205Finis.
206""" #"
207# ^
208# |----helps out font-lock
209
210#
211# Import our required modules
Tim Peters88869f92001-01-14 23:36:06 +0000212#
Martin v. Löwis02d893c2001-08-02 07:15:29 +0000213import string
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000214
215try:
216 from cPickle import dumps, loads
217except ImportError:
218 from pickle import dumps, loads
219
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000220import re, warnings
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000221
Skip Montanaroe99d5ea2001-01-20 19:54:20 +0000222__all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
223 "SmartCookie","Cookie"]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000224
Fred Draked451ec12002-04-26 02:29:55 +0000225_nulljoin = ''.join
Georg Brandl532efab2005-08-24 22:34:21 +0000226_semispacejoin = '; '.join
Georg Brandl8246c432005-08-25 07:32:42 +0000227_spacejoin = ' '.join
Fred Draked451ec12002-04-26 02:29:55 +0000228
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000229#
230# Define an exception visible to External modules
231#
232class CookieError(Exception):
233 pass
234
235
236# These quoting routines conform to the RFC2109 specification, which in
237# turn references the character definitions from RFC2068. They provide
238# a two-way quoting algorithm. Any non-text character is translated
239# into a 4 character sequence: a forward-slash followed by the
240# three-digit octal equivalent of the character. Any '\' or '"' is
241# quoted with a preceeding '\' slash.
Tim Peters88869f92001-01-14 23:36:06 +0000242#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000243# These are taken from RFC2068 and RFC2109.
244# _LegalChars is the list of chars which don't require "'s
245# _Translator hash-table for fast quoting
246#
Fred Drake79e75e12001-07-20 19:05:50 +0000247_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000248_Translator = {
249 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
250 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
251 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
252 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
253 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
254 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
255 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
256 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
257 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
258 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
259 '\036' : '\\036', '\037' : '\\037',
260
261 '"' : '\\"', '\\' : '\\\\',
262
263 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
264 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
265 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
266 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
267 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
268 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
269 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
270 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
271 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
272 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
273 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
274 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
275 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
276 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
277 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
278 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
279 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
280 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
281 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
282 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
283 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
284 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
285 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
286 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
287 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
288 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
289 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
290 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
291 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
292 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
293 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
294 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
295 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
296 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
297 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
298 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
299 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
300 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
301 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
302 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
303 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
304 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
305 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
306 }
307
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000308def _quote(str, LegalChars=_LegalChars):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000309 #
310 # If the string does not need to be double-quoted,
311 # then just return the string. Otherwise, surround
312 # the string in doublequotes and precede quote (with a \)
313 # special characters.
314 #
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000315 if len(filter(LegalChars.__contains__, str)) == len(str):
Fred Drakeff5364a2000-08-24 14:40:35 +0000316 return str
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000317 else:
Fred Draked451ec12002-04-26 02:29:55 +0000318 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000319# end _quote
320
321
322_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
323_QuotePatt = re.compile(r"[\\].")
324
Fred Draked451ec12002-04-26 02:29:55 +0000325def _unquote(str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000326 # If there aren't any doublequotes,
327 # then there can't be any special characters. See RFC 2109.
328 if len(str) < 2:
329 return str
330 if str[0] != '"' or str[-1] != '"':
331 return str
332
333 # We have to assume that we must decode this string.
334 # Down to work.
335
336 # Remove the "s
337 str = str[1:-1]
Fred Drakeff5364a2000-08-24 14:40:35 +0000338
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000339 # Check for special sequences. Examples:
340 # \012 --> \n
341 # \" --> "
342 #
343 i = 0
344 n = len(str)
345 res = []
346 while 0 <= i < n:
347 Omatch = _OctalPatt.search(str, i)
348 Qmatch = _QuotePatt.search(str, i)
349 if not Omatch and not Qmatch: # Neither matched
350 res.append(str[i:])
351 break
352 # else:
353 j = k = -1
354 if Omatch: j = Omatch.start(0)
355 if Qmatch: k = Qmatch.start(0)
356 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
357 res.append(str[i:k])
358 res.append(str[k+1])
359 i = k+2
360 else: # OctalPatt matched
361 res.append(str[i:j])
Fred Draked451ec12002-04-26 02:29:55 +0000362 res.append( chr( int(str[j+1:j+4], 8) ) )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000363 i = j+4
Fred Draked451ec12002-04-26 02:29:55 +0000364 return _nulljoin(res)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000365# end _unquote
366
367# The _getdate() routine is used to set the expiration time in
368# the cookie's HTTP header. By default, _getdate() returns the
Tim Peters88869f92001-01-14 23:36:06 +0000369# current time in the appropriate "expires" format for a
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000370# Set-Cookie header. The one optional argument is an offset from
371# now, in seconds. For example, an offset of -3600 means "one hour ago".
372# The offset may be a floating point number.
373#
374
375_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
376
377_monthname = [None,
378 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
379 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
380
381def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
382 from time import gmtime, time
383 now = time()
384 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
385 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
386 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
387
388
389#
390# A class to hold ONE key,value pair.
391# In a cookie, each such pair may have several attributes.
392# so this class is used to keep the attributes associated
393# with the appropriate key,value pair.
394# This class also includes a coded_value attribute, which
395# is used to hold the network representation of the
396# value. This is most useful when Python objects are
397# pickled for network transit.
398#
399
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000400class Morsel(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000401 # RFC 2109 lists these attributes as reserved:
402 # path comment domain
403 # max-age secure version
Tim Peters88869f92001-01-14 23:36:06 +0000404 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000405 # For historical reasons, these attributes are also reserved:
406 # expires
407 #
408 # This dictionary provides a mapping from the lowercase
409 # variant on the left to the appropriate traditional
410 # formatting on the right.
411 _reserved = { "expires" : "expires",
412 "path" : "Path",
413 "comment" : "Comment",
414 "domain" : "Domain",
415 "max-age" : "Max-Age",
416 "secure" : "secure",
417 "version" : "Version",
418 }
Fred Drakeff5364a2000-08-24 14:40:35 +0000419
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000420 def __init__(self):
421 # Set defaults
422 self.key = self.value = self.coded_value = None
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000423
424 # Set default attributes
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000425 for K in self._reserved:
426 dict.__setitem__(self, K, "")
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000427 # end __init__
428
429 def __setitem__(self, K, V):
Fred Draked451ec12002-04-26 02:29:55 +0000430 K = K.lower()
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000431 if not K in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000432 raise CookieError("Invalid Attribute %s" % K)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000433 dict.__setitem__(self, K, V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000434 # end __setitem__
435
436 def isReservedKey(self, K):
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000437 return K.lower() in self._reserved
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000438 # end isReservedKey
439
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000440 def set(self, key, val, coded_val, LegalChars=_LegalChars):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000441 # First we verify that the key isn't a reserved word
442 # Second we make sure it only contains legal characters
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000443 if key.lower() in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000444 raise CookieError("Attempt to set a reserved key: %s" % key)
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000445 if len(filter(LegalChars.__contains__, key)) != len(key):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000446 raise CookieError("Illegal key value: %s" % key)
447
448 # It's a good key, so save it.
449 self.key = key
450 self.value = val
451 self.coded_value = coded_val
452 # end set
453
454 def output(self, attrs=None, header = "Set-Cookie:"):
455 return "%s %s" % ( header, self.OutputString(attrs) )
456
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000457 __str__ = output
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000458
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000459 def __repr__(self):
460 return '<%s: %s=%s>' % (self.__class__.__name__,
461 self.key, repr(self.value) )
Fred Drakeff5364a2000-08-24 14:40:35 +0000462
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000463 def js_output(self, attrs=None):
464 # Print javascript
465 return """
Georg Brandl03a33ea2005-06-26 21:02:49 +0000466 <script type="text/javascript">
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000467 <!-- begin hiding
Georg Brandl03a33ea2005-06-26 21:02:49 +0000468 document.cookie = \"%s\";
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000469 // end hiding -->
470 </script>
471 """ % ( self.OutputString(attrs), )
472 # end js_output()
473
474 def OutputString(self, attrs=None):
475 # Build up our result
476 #
477 result = []
478 RA = result.append
Fred Drakeff5364a2000-08-24 14:40:35 +0000479
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000480 # First, the key=value pair
Georg Brandl532efab2005-08-24 22:34:21 +0000481 RA("%s=%s" % (self.key, self.coded_value))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000482
483 # Now add any defined attributes
Fred Drake8152d322000-12-12 23:20:45 +0000484 if attrs is None:
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000485 attrs = self._reserved
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000486 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000487 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000488 if V == "": continue
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000489 if K not in attrs: continue
490 if K == "expires" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000491 RA("%s=%s" % (self._reserved[K], _getdate(V)))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000492 elif K == "max-age" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000493 RA("%s=%d" % (self._reserved[K], V))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000494 elif K == "secure":
Georg Brandl532efab2005-08-24 22:34:21 +0000495 RA(str(self._reserved[K]))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000496 else:
Georg Brandl532efab2005-08-24 22:34:21 +0000497 RA("%s=%s" % (self._reserved[K], V))
Fred Drakeff5364a2000-08-24 14:40:35 +0000498
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000499 # Return the result
Georg Brandl532efab2005-08-24 22:34:21 +0000500 return _semispacejoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000501 # end OutputString
502# end Morsel class
503
504
505
506#
507# Pattern for finding cookie
508#
509# This used to be strict parsing based on the RFC2109 and RFC2068
510# specifications. I have since discovered that MSIE 3.0x doesn't
511# follow the character rules outlined in those specs. As a
512# result, the parsing rules here are less strict.
513#
514
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000515_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000516_CookiePattern = re.compile(
517 r"(?x)" # This is a Verbose pattern
518 r"(?P<key>" # Start of group 'key'
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000519 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000520 r")" # End of group 'key'
521 r"\s*=\s*" # Equal Sign
522 r"(?P<val>" # Start of group 'val'
523 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
524 r"|" # or
525 ""+ _LegalCharsPatt +"*" # Any word or empty string
526 r")" # End of group 'val'
527 r"\s*;?" # Probably ending in a semi-colon
528 )
529
530
531# At long last, here is the cookie class.
532# Using this class is almost just like using a dictionary.
533# See this module's docstring for example usage.
534#
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000535class BaseCookie(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000536 # A container class for a set of Morsels
537 #
Fred Drakeff5364a2000-08-24 14:40:35 +0000538
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000539 def value_decode(self, val):
540 """real_value, coded_value = value_decode(STRING)
541 Called prior to setting a cookie's value from the network
542 representation. The VALUE is the value read from HTTP
543 header.
544 Override this function to modify the behavior of cookies.
545 """
546 return val, val
547 # end value_encode
548
549 def value_encode(self, val):
550 """real_value, coded_value = value_encode(VALUE)
551 Called prior to setting a cookie's value from the dictionary
552 representation. The VALUE is the value being assigned.
553 Override this function to modify the behavior of cookies.
554 """
555 strval = str(val)
556 return strval, strval
557 # end value_encode
Fred Drakeff5364a2000-08-24 14:40:35 +0000558
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000559 def __init__(self, input=None):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000560 if input: self.load(input)
561 # end __init__
562
563 def __set(self, key, real_value, coded_value):
564 """Private method for setting a cookie's value"""
565 M = self.get(key, Morsel())
566 M.set(key, real_value, coded_value)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000567 dict.__setitem__(self, key, M)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000568 # end __set
569
570 def __setitem__(self, key, value):
571 """Dictionary style assignment."""
572 rval, cval = self.value_encode(value)
573 self.__set(key, rval, cval)
574 # end __setitem__
575
Georg Brandl532efab2005-08-24 22:34:21 +0000576 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000577 """Return a string suitable for HTTP."""
578 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000579 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000580 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000581 result.append( V.output(attrs, header) )
Fred Draked451ec12002-04-26 02:29:55 +0000582 return sep.join(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000583 # end output
584
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000585 __str__ = output
586
587 def __repr__(self):
588 L = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000589 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000590 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000591 L.append( '%s=%s' % (K,repr(V.value) ) )
Georg Brandl8246c432005-08-25 07:32:42 +0000592 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
Fred Drakeff5364a2000-08-24 14:40:35 +0000593
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000594 def js_output(self, attrs=None):
595 """Return a string suitable for JavaScript."""
596 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000597 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000598 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000599 result.append( V.js_output(attrs) )
Fred Draked451ec12002-04-26 02:29:55 +0000600 return _nulljoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000601 # end js_output
602
603 def load(self, rawdata):
604 """Load cookies from a string (presumably HTTP_COOKIE) or
605 from a dictionary. Loading cookies from a dictionary 'd'
606 is equivalent to calling:
607 map(Cookie.__setitem__, d.keys(), d.values())
608 """
609 if type(rawdata) == type(""):
610 self.__ParseString(rawdata)
611 else:
612 self.update(rawdata)
613 return
614 # end load()
Fred Drakeff5364a2000-08-24 14:40:35 +0000615
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000616 def __ParseString(self, str, patt=_CookiePattern):
617 i = 0 # Our starting point
618 n = len(str) # Length of string
619 M = None # current morsel
620
621 while 0 <= i < n:
622 # Start looking for a cookie
623 match = patt.search(str, i)
624 if not match: break # No more cookies
625
626 K,V = match.group("key"), match.group("val")
627 i = match.end(0)
628
629 # Parse the key, value in case it's metainfo
630 if K[0] == "$":
631 # We ignore attributes which pertain to the cookie
632 # mechanism as a whole. See RFC 2109.
633 # (Does anyone care?)
634 if M:
635 M[ K[1:] ] = V
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000636 elif K.lower() in Morsel._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000637 if M:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000638 M[ K ] = _unquote(V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000639 else:
640 rval, cval = self.value_decode(V)
641 self.__set(K, rval, cval)
642 M = self[K]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000643 # end __ParseString
644# end BaseCookie class
645
646class SimpleCookie(BaseCookie):
647 """SimpleCookie
648 SimpleCookie supports strings as cookie values. When setting
649 the value using the dictionary assignment notation, SimpleCookie
650 calls the builtin str() to convert the value to a string. Values
651 received from HTTP are kept as strings.
652 """
653 def value_decode(self, val):
654 return _unquote( val ), val
655 def value_encode(self, val):
656 strval = str(val)
657 return strval, _quote( strval )
658# end SimpleCookie
659
660class SerialCookie(BaseCookie):
661 """SerialCookie
662 SerialCookie supports arbitrary objects as cookie values. All
663 values are serialized (using cPickle) before being sent to the
664 client. All incoming values are assumed to be valid Pickle
665 representations. IF AN INCOMING VALUE IS NOT IN A VALID PICKLE
666 FORMAT, THEN AN EXCEPTION WILL BE RAISED.
667
668 Note: Large cookie values add overhead because they must be
669 retransmitted on every HTTP transaction.
Fred Drakeff5364a2000-08-24 14:40:35 +0000670
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000671 Note: HTTP has a 2k limit on the size of a cookie. This class
672 does not check for this limit, so be careful!!!
673 """
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000674 def __init__(self, input=None):
675 warnings.warn("SerialCookie class is insecure; do not use it",
676 DeprecationWarning)
677 BaseCookie.__init__(self, input)
678 # end __init__
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000679 def value_decode(self, val):
680 # This could raise an exception!
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000681 return loads( _unquote(val).encode('latin-1') ), val
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000682 def value_encode(self, val):
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000683 return val, _quote( dumps(val).decode('latin-1') )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000684# end SerialCookie
685
686class SmartCookie(BaseCookie):
687 """SmartCookie
688 SmartCookie supports arbitrary objects as cookie values. If the
689 object is a string, then it is quoted. If the object is not a
690 string, however, then SmartCookie will use cPickle to serialize
691 the object into a string representation.
692
693 Note: Large cookie values add overhead because they must be
694 retransmitted on every HTTP transaction.
Fred Drakeff5364a2000-08-24 14:40:35 +0000695
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000696 Note: HTTP has a 2k limit on the size of a cookie. This class
697 does not check for this limit, so be careful!!!
698 """
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000699 def __init__(self, input=None):
700 warnings.warn("Cookie/SmartCookie class is insecure; do not use it",
701 DeprecationWarning)
702 BaseCookie.__init__(self, input)
703 # end __init__
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000704 def value_decode(self, val):
705 strval = _unquote(val)
706 try:
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000707 return loads(strval.encode('latin-1')), val
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000708 except:
709 return strval, val
710 def value_encode(self, val):
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000711 if isinstance(val, str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000712 return val, _quote(val)
713 else:
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000714 return val, _quote( dumps(val).decode('latin-1') )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000715# end SmartCookie
716
717
718###########################################################
719# Backwards Compatibility: Don't break any existing code!
720
721# We provide Cookie() as an alias for SmartCookie()
722Cookie = SmartCookie
723
724#
725###########################################################
726
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000727def _test():
728 import doctest, Cookie
729 return doctest.testmod(Cookie)
730
731if __name__ == "__main__":
732 _test()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000733
734
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000735#Local Variables:
736#tab-width: 4
737#end: