blob: b84c259fd3557d4153d70caab5e0247b95a28bc4 [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
Georg Brandl24420152008-05-26 16:32:26 +000051 >>> from http import cookies
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000052
Georg Brandl61013952008-05-28 15:56:30 +000053Most of the time you start by creating a cookie.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000054
Georg Brandl24420152008-05-26 16:32:26 +000055 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000056
57Once you've created your Cookie, you can add values just as if it were
58a dictionary.
59
Georg Brandl61013952008-05-28 15:56:30 +000060 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000061 >>> C["fig"] = "newton"
62 >>> C["sugar"] = "wafer"
Georg Brandl532efab2005-08-24 22:34:21 +000063 >>> C.output()
64 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000065
66Notice that the printable representation of a Cookie is the
67appropriate format for a Set-Cookie: header. This is the
68default behavior. You can change the header and printed
Walter Dörwaldf0dfc7a2003-10-20 14:01:56 +000069attributes by using the .output() function
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000070
Georg Brandl61013952008-05-28 15:56:30 +000071 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000072 >>> C["rocky"] = "road"
73 >>> C["rocky"]["path"] = "/cookie"
Guido van Rossumfff80df2007-02-09 20:33:44 +000074 >>> print(C.output(header="Cookie:"))
Georg Brandl532efab2005-08-24 22:34:21 +000075 Cookie: rocky=road; Path=/cookie
Guido van Rossumfff80df2007-02-09 20:33:44 +000076 >>> print(C.output(attrs=[], header="Cookie:"))
Georg Brandl532efab2005-08-24 22:34:21 +000077 Cookie: rocky=road
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000078
79The load() method of a Cookie extracts cookies from a string. In a
80CGI script, you would use this method to extract the cookies from the
81HTTP_COOKIE environment variable.
82
Georg Brandl61013952008-05-28 15:56:30 +000083 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000084 >>> C.load("chips=ahoy; vienna=finger")
Georg Brandl532efab2005-08-24 22:34:21 +000085 >>> C.output()
86 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000087
88The load() method is darn-tootin smart about identifying cookies
89within a string. Escaped quotation marks, nested semicolons, and other
90such trickeries do not confuse it.
91
Georg Brandl61013952008-05-28 15:56:30 +000092 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000093 >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
Guido van Rossumfff80df2007-02-09 20:33:44 +000094 >>> print(C)
Georg Brandl532efab2005-08-24 22:34:21 +000095 Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +000096
97Each element of the Cookie also supports all of the RFC 2109
98Cookie attributes. Here's an example which sets the Path
99attribute.
100
Georg Brandl61013952008-05-28 15:56:30 +0000101 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000102 >>> C["oreo"] = "doublestuff"
103 >>> C["oreo"]["path"] = "/"
Guido van Rossumfff80df2007-02-09 20:33:44 +0000104 >>> print(C)
Georg Brandl532efab2005-08-24 22:34:21 +0000105 Set-Cookie: oreo=doublestuff; Path=/
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000106
107Each dictionary element has a 'value' attribute, which gives you
Tim Peters88869f92001-01-14 23:36:06 +0000108back the value associated with the key.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000109
Georg Brandl61013952008-05-28 15:56:30 +0000110 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000111 >>> C["twix"] = "none for you"
112 >>> C["twix"].value
113 'none for you'
114
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000115The SimpleCookie expects that all values should be standard strings.
116Just to be sure, SimpleCookie invokes the str() builtin to convert
117the value to a string, when the values are set dictionary-style.
118
Georg Brandl24420152008-05-26 16:32:26 +0000119 >>> C = cookies.SimpleCookie()
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000120 >>> C["number"] = 7
121 >>> C["string"] = "seven"
122 >>> C["number"].value
123 '7'
124 >>> C["string"].value
125 'seven'
Georg Brandl532efab2005-08-24 22:34:21 +0000126 >>> C.output()
127 'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000128
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000129Finis.
130""" #"
131# ^
132# |----helps out font-lock
133
134#
135# Import our required modules
Tim Peters88869f92001-01-14 23:36:06 +0000136#
Martin v. Löwis02d893c2001-08-02 07:15:29 +0000137import string
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000138
Guido van Rossum99603b02007-07-20 00:22:32 +0000139from pickle import dumps, loads
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000140
Andrew M. Kuchling7877a762002-12-29 16:44:31 +0000141import re, warnings
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000142
Georg Brandl61013952008-05-28 15:56:30 +0000143__all__ = ["CookieError", "BaseCookie", "SimpleCookie"]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000144
Fred Draked451ec12002-04-26 02:29:55 +0000145_nulljoin = ''.join
Georg Brandl532efab2005-08-24 22:34:21 +0000146_semispacejoin = '; '.join
Georg Brandl8246c432005-08-25 07:32:42 +0000147_spacejoin = ' '.join
Fred Draked451ec12002-04-26 02:29:55 +0000148
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000149#
150# Define an exception visible to External modules
151#
152class CookieError(Exception):
153 pass
154
155
156# These quoting routines conform to the RFC2109 specification, which in
157# turn references the character definitions from RFC2068. They provide
158# a two-way quoting algorithm. Any non-text character is translated
159# into a 4 character sequence: a forward-slash followed by the
160# three-digit octal equivalent of the character. Any '\' or '"' is
161# quoted with a preceeding '\' slash.
Tim Peters88869f92001-01-14 23:36:06 +0000162#
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000163# These are taken from RFC2068 and RFC2109.
164# _LegalChars is the list of chars which don't require "'s
165# _Translator hash-table for fast quoting
166#
Fred Drake79e75e12001-07-20 19:05:50 +0000167_LegalChars = string.ascii_letters + string.digits + "!#$%&'*+-.^_`|~"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000168_Translator = {
169 '\000' : '\\000', '\001' : '\\001', '\002' : '\\002',
170 '\003' : '\\003', '\004' : '\\004', '\005' : '\\005',
171 '\006' : '\\006', '\007' : '\\007', '\010' : '\\010',
172 '\011' : '\\011', '\012' : '\\012', '\013' : '\\013',
173 '\014' : '\\014', '\015' : '\\015', '\016' : '\\016',
174 '\017' : '\\017', '\020' : '\\020', '\021' : '\\021',
175 '\022' : '\\022', '\023' : '\\023', '\024' : '\\024',
176 '\025' : '\\025', '\026' : '\\026', '\027' : '\\027',
177 '\030' : '\\030', '\031' : '\\031', '\032' : '\\032',
178 '\033' : '\\033', '\034' : '\\034', '\035' : '\\035',
179 '\036' : '\\036', '\037' : '\\037',
180
181 '"' : '\\"', '\\' : '\\\\',
182
183 '\177' : '\\177', '\200' : '\\200', '\201' : '\\201',
184 '\202' : '\\202', '\203' : '\\203', '\204' : '\\204',
185 '\205' : '\\205', '\206' : '\\206', '\207' : '\\207',
186 '\210' : '\\210', '\211' : '\\211', '\212' : '\\212',
187 '\213' : '\\213', '\214' : '\\214', '\215' : '\\215',
188 '\216' : '\\216', '\217' : '\\217', '\220' : '\\220',
189 '\221' : '\\221', '\222' : '\\222', '\223' : '\\223',
190 '\224' : '\\224', '\225' : '\\225', '\226' : '\\226',
191 '\227' : '\\227', '\230' : '\\230', '\231' : '\\231',
192 '\232' : '\\232', '\233' : '\\233', '\234' : '\\234',
193 '\235' : '\\235', '\236' : '\\236', '\237' : '\\237',
194 '\240' : '\\240', '\241' : '\\241', '\242' : '\\242',
195 '\243' : '\\243', '\244' : '\\244', '\245' : '\\245',
196 '\246' : '\\246', '\247' : '\\247', '\250' : '\\250',
197 '\251' : '\\251', '\252' : '\\252', '\253' : '\\253',
198 '\254' : '\\254', '\255' : '\\255', '\256' : '\\256',
199 '\257' : '\\257', '\260' : '\\260', '\261' : '\\261',
200 '\262' : '\\262', '\263' : '\\263', '\264' : '\\264',
201 '\265' : '\\265', '\266' : '\\266', '\267' : '\\267',
202 '\270' : '\\270', '\271' : '\\271', '\272' : '\\272',
203 '\273' : '\\273', '\274' : '\\274', '\275' : '\\275',
204 '\276' : '\\276', '\277' : '\\277', '\300' : '\\300',
205 '\301' : '\\301', '\302' : '\\302', '\303' : '\\303',
206 '\304' : '\\304', '\305' : '\\305', '\306' : '\\306',
207 '\307' : '\\307', '\310' : '\\310', '\311' : '\\311',
208 '\312' : '\\312', '\313' : '\\313', '\314' : '\\314',
209 '\315' : '\\315', '\316' : '\\316', '\317' : '\\317',
210 '\320' : '\\320', '\321' : '\\321', '\322' : '\\322',
211 '\323' : '\\323', '\324' : '\\324', '\325' : '\\325',
212 '\326' : '\\326', '\327' : '\\327', '\330' : '\\330',
213 '\331' : '\\331', '\332' : '\\332', '\333' : '\\333',
214 '\334' : '\\334', '\335' : '\\335', '\336' : '\\336',
215 '\337' : '\\337', '\340' : '\\340', '\341' : '\\341',
216 '\342' : '\\342', '\343' : '\\343', '\344' : '\\344',
217 '\345' : '\\345', '\346' : '\\346', '\347' : '\\347',
218 '\350' : '\\350', '\351' : '\\351', '\352' : '\\352',
219 '\353' : '\\353', '\354' : '\\354', '\355' : '\\355',
220 '\356' : '\\356', '\357' : '\\357', '\360' : '\\360',
221 '\361' : '\\361', '\362' : '\\362', '\363' : '\\363',
222 '\364' : '\\364', '\365' : '\\365', '\366' : '\\366',
223 '\367' : '\\367', '\370' : '\\370', '\371' : '\\371',
224 '\372' : '\\372', '\373' : '\\373', '\374' : '\\374',
225 '\375' : '\\375', '\376' : '\\376', '\377' : '\\377'
226 }
227
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000228def _quote(str, LegalChars=_LegalChars):
Georg Brandl9cf32a12009-09-04 08:28:01 +0000229 r"""Quote a string for use in a cookie header.
230
231 If the string does not need to be double-quoted, then just return the
232 string. Otherwise, surround the string in doublequotes and quote
233 (with a \) special characters.
234 """
Guido van Rossum0c41e882007-07-03 16:46:40 +0000235 if all(c in LegalChars for c in str):
Fred Drakeff5364a2000-08-24 14:40:35 +0000236 return str
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000237 else:
Fred Draked451ec12002-04-26 02:29:55 +0000238 return '"' + _nulljoin( map(_Translator.get, str, str) ) + '"'
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000239
240
241_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
242_QuotePatt = re.compile(r"[\\].")
243
Fred Draked451ec12002-04-26 02:29:55 +0000244def _unquote(str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000245 # If there aren't any doublequotes,
246 # then there can't be any special characters. See RFC 2109.
247 if len(str) < 2:
248 return str
249 if str[0] != '"' or str[-1] != '"':
250 return str
251
252 # We have to assume that we must decode this string.
253 # Down to work.
254
255 # Remove the "s
256 str = str[1:-1]
Fred Drakeff5364a2000-08-24 14:40:35 +0000257
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000258 # Check for special sequences. Examples:
259 # \012 --> \n
260 # \" --> "
261 #
262 i = 0
263 n = len(str)
264 res = []
265 while 0 <= i < n:
266 Omatch = _OctalPatt.search(str, i)
267 Qmatch = _QuotePatt.search(str, i)
268 if not Omatch and not Qmatch: # Neither matched
269 res.append(str[i:])
270 break
271 # else:
272 j = k = -1
273 if Omatch: j = Omatch.start(0)
274 if Qmatch: k = Qmatch.start(0)
275 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
276 res.append(str[i:k])
277 res.append(str[k+1])
278 i = k+2
279 else: # OctalPatt matched
280 res.append(str[i:j])
Fred Draked451ec12002-04-26 02:29:55 +0000281 res.append( chr( int(str[j+1:j+4], 8) ) )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000282 i = j+4
Fred Draked451ec12002-04-26 02:29:55 +0000283 return _nulljoin(res)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000284
285# The _getdate() routine is used to set the expiration time in
286# the cookie's HTTP header. By default, _getdate() returns the
Tim Peters88869f92001-01-14 23:36:06 +0000287# current time in the appropriate "expires" format for a
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000288# Set-Cookie header. The one optional argument is an offset from
289# now, in seconds. For example, an offset of -3600 means "one hour ago".
290# The offset may be a floating point number.
291#
292
293_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
294
295_monthname = [None,
296 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
297 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
298
299def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
300 from time import gmtime, time
301 now = time()
302 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
303 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
304 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
305
306
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000307class Morsel(dict):
Georg Brandl9cf32a12009-09-04 08:28:01 +0000308 """A class to hold ONE key,value pair.
309
310 In a cookie, each such pair may have several attributes, so this class is
311 used to keep the attributes associated with the appropriate key,value pair.
312 This class also includes a coded_value attribute, which is used to hold
313 the network representation of the value. This is most useful when Python
314 objects are pickled for network transit.
315 """
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000316 # RFC 2109 lists these attributes as reserved:
317 # path comment domain
318 # max-age secure version
Tim Peters88869f92001-01-14 23:36:06 +0000319 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000320 # For historical reasons, these attributes are also reserved:
321 # expires
322 #
Benjamin Peterson35e661c2008-09-06 19:37:35 +0000323 # This is an extension from Microsoft:
324 # httponly
325 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000326 # This dictionary provides a mapping from the lowercase
327 # variant on the left to the appropriate traditional
328 # formatting on the right.
329 _reserved = { "expires" : "expires",
330 "path" : "Path",
331 "comment" : "Comment",
332 "domain" : "Domain",
333 "max-age" : "Max-Age",
334 "secure" : "secure",
Benjamin Peterson35e661c2008-09-06 19:37:35 +0000335 "httponly" : "httponly",
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000336 "version" : "Version",
337 }
Fred Drakeff5364a2000-08-24 14:40:35 +0000338
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000339 def __init__(self):
340 # Set defaults
341 self.key = self.value = self.coded_value = None
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000342
343 # Set default attributes
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000344 for K in self._reserved:
345 dict.__setitem__(self, K, "")
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000346
347 def __setitem__(self, K, V):
Fred Draked451ec12002-04-26 02:29:55 +0000348 K = K.lower()
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000349 if not K in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000350 raise CookieError("Invalid Attribute %s" % K)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000351 dict.__setitem__(self, K, V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000352
353 def isReservedKey(self, K):
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000354 return K.lower() in self._reserved
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000355
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000356 def set(self, key, val, coded_val, LegalChars=_LegalChars):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000357 # First we verify that the key isn't a reserved word
358 # Second we make sure it only contains legal characters
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000359 if key.lower() in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000360 raise CookieError("Attempt to set a reserved key: %s" % key)
Guido van Rossum0c41e882007-07-03 16:46:40 +0000361 if any(c not in LegalChars for c in key):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000362 raise CookieError("Illegal key value: %s" % key)
363
364 # It's a good key, so save it.
365 self.key = key
366 self.value = val
367 self.coded_value = coded_val
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000368
369 def output(self, attrs=None, header = "Set-Cookie:"):
370 return "%s %s" % ( header, self.OutputString(attrs) )
371
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000372 __str__ = output
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000373
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000374 def __repr__(self):
375 return '<%s: %s=%s>' % (self.__class__.__name__,
376 self.key, repr(self.value) )
Fred Drakeff5364a2000-08-24 14:40:35 +0000377
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000378 def js_output(self, attrs=None):
379 # Print javascript
380 return """
Georg Brandl03a33ea2005-06-26 21:02:49 +0000381 <script type="text/javascript">
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000382 <!-- begin hiding
Georg Brandl03a33ea2005-06-26 21:02:49 +0000383 document.cookie = \"%s\";
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000384 // end hiding -->
385 </script>
Senthil Kumaran3e2ea792009-04-02 03:02:03 +0000386 """ % ( self.OutputString(attrs).replace('"',r'\"'))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000387
388 def OutputString(self, attrs=None):
389 # Build up our result
390 #
391 result = []
392 RA = result.append
Fred Drakeff5364a2000-08-24 14:40:35 +0000393
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000394 # First, the key=value pair
Georg Brandl532efab2005-08-24 22:34:21 +0000395 RA("%s=%s" % (self.key, self.coded_value))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000396
397 # Now add any defined attributes
Fred Drake8152d322000-12-12 23:20:45 +0000398 if attrs is None:
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000399 attrs = self._reserved
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000400 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000401 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000402 if V == "": continue
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000403 if K not in attrs: continue
404 if K == "expires" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000405 RA("%s=%s" % (self._reserved[K], _getdate(V)))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000406 elif K == "max-age" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000407 RA("%s=%d" % (self._reserved[K], V))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000408 elif K == "secure":
Georg Brandl532efab2005-08-24 22:34:21 +0000409 RA(str(self._reserved[K]))
Benjamin Peterson35e661c2008-09-06 19:37:35 +0000410 elif K == "httponly":
411 RA(str(self._reserved[K]))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000412 else:
Georg Brandl532efab2005-08-24 22:34:21 +0000413 RA("%s=%s" % (self._reserved[K], V))
Fred Drakeff5364a2000-08-24 14:40:35 +0000414
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000415 # Return the result
Georg Brandl532efab2005-08-24 22:34:21 +0000416 return _semispacejoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000417
418
419#
420# Pattern for finding cookie
421#
422# This used to be strict parsing based on the RFC2109 and RFC2068
423# specifications. I have since discovered that MSIE 3.0x doesn't
424# follow the character rules outlined in those specs. As a
425# result, the parsing rules here are less strict.
426#
427
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000428_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000429_CookiePattern = re.compile(
430 r"(?x)" # This is a Verbose pattern
431 r"(?P<key>" # Start of group 'key'
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000432 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000433 r")" # End of group 'key'
434 r"\s*=\s*" # Equal Sign
435 r"(?P<val>" # Start of group 'val'
436 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
437 r"|" # or
438 ""+ _LegalCharsPatt +"*" # Any word or empty string
439 r")" # End of group 'val'
440 r"\s*;?" # Probably ending in a semi-colon
Antoine Pitroufd036452008-08-19 17:56:33 +0000441 , re.ASCII) # May be removed if safe.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000442
443
444# At long last, here is the cookie class.
445# Using this class is almost just like using a dictionary.
446# See this module's docstring for example usage.
447#
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000448class BaseCookie(dict):
Georg Brandl9cf32a12009-09-04 08:28:01 +0000449 """A container class for a set of Morsels."""
Fred Drakeff5364a2000-08-24 14:40:35 +0000450
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000451 def value_decode(self, val):
452 """real_value, coded_value = value_decode(STRING)
453 Called prior to setting a cookie's value from the network
454 representation. The VALUE is the value read from HTTP
455 header.
456 Override this function to modify the behavior of cookies.
457 """
458 return val, val
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000459
460 def value_encode(self, val):
461 """real_value, coded_value = value_encode(VALUE)
462 Called prior to setting a cookie's value from the dictionary
463 representation. The VALUE is the value being assigned.
464 Override this function to modify the behavior of cookies.
465 """
466 strval = str(val)
467 return strval, strval
Fred Drakeff5364a2000-08-24 14:40:35 +0000468
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000469 def __init__(self, input=None):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000470 if input: self.load(input)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000471
472 def __set(self, key, real_value, coded_value):
473 """Private method for setting a cookie's value"""
474 M = self.get(key, Morsel())
475 M.set(key, real_value, coded_value)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000476 dict.__setitem__(self, key, M)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000477
478 def __setitem__(self, key, value):
479 """Dictionary style assignment."""
480 rval, cval = self.value_encode(value)
481 self.__set(key, rval, cval)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000482
Georg Brandl532efab2005-08-24 22:34:21 +0000483 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000484 """Return a string suitable for HTTP."""
485 result = []
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. Kuchling52ea8722000-08-19 13:01:19 +0000488 result.append( V.output(attrs, header) )
Fred Draked451ec12002-04-26 02:29:55 +0000489 return sep.join(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000490
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000491 __str__ = output
492
493 def __repr__(self):
494 L = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000495 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000496 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000497 L.append( '%s=%s' % (K,repr(V.value) ) )
Georg Brandl8246c432005-08-25 07:32:42 +0000498 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
Fred Drakeff5364a2000-08-24 14:40:35 +0000499
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000500 def js_output(self, attrs=None):
501 """Return a string suitable for JavaScript."""
502 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000503 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000504 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000505 result.append( V.js_output(attrs) )
Fred Draked451ec12002-04-26 02:29:55 +0000506 return _nulljoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000507
508 def load(self, rawdata):
509 """Load cookies from a string (presumably HTTP_COOKIE) or
510 from a dictionary. Loading cookies from a dictionary 'd'
511 is equivalent to calling:
512 map(Cookie.__setitem__, d.keys(), d.values())
513 """
514 if type(rawdata) == type(""):
515 self.__ParseString(rawdata)
516 else:
517 self.update(rawdata)
518 return
Fred Drakeff5364a2000-08-24 14:40:35 +0000519
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000520 def __ParseString(self, str, patt=_CookiePattern):
521 i = 0 # Our starting point
522 n = len(str) # Length of string
523 M = None # current morsel
524
525 while 0 <= i < n:
526 # Start looking for a cookie
527 match = patt.search(str, i)
528 if not match: break # No more cookies
529
530 K,V = match.group("key"), match.group("val")
531 i = match.end(0)
532
533 # Parse the key, value in case it's metainfo
534 if K[0] == "$":
535 # We ignore attributes which pertain to the cookie
536 # mechanism as a whole. See RFC 2109.
537 # (Does anyone care?)
538 if M:
539 M[ K[1:] ] = V
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000540 elif K.lower() in Morsel._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000541 if M:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000542 M[ K ] = _unquote(V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000543 else:
544 rval, cval = self.value_decode(V)
545 self.__set(K, rval, cval)
546 M = self[K]
Georg Brandl4eff9f72009-09-04 08:22:00 +0000547
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000548
549class SimpleCookie(BaseCookie):
Georg Brandl9cf32a12009-09-04 08:28:01 +0000550 """
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000551 SimpleCookie supports strings as cookie values. When setting
552 the value using the dictionary assignment notation, SimpleCookie
553 calls the builtin str() to convert the value to a string. Values
554 received from HTTP are kept as strings.
555 """
556 def value_decode(self, val):
557 return _unquote( val ), val
558 def value_encode(self, val):
559 strval = str(val)
560 return strval, _quote( strval )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000561
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000562###########################################################
563
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000564def _test():
Georg Brandl24420152008-05-26 16:32:26 +0000565 import doctest, http.cookies
566 return doctest.testmod(http.cookies)
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000567
568if __name__ == "__main__":
569 _test()