blob: 695161a380f857ff8ab7096f4c1fa584b6472e92 [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):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000229 #
230 # If the string does not need to be double-quoted,
231 # then just return the string. Otherwise, surround
232 # the string in doublequotes and precede quote (with a \)
233 # 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# end _quote
240
241
242_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")
243_QuotePatt = re.compile(r"[\\].")
244
Fred Draked451ec12002-04-26 02:29:55 +0000245def _unquote(str):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000246 # If there aren't any doublequotes,
247 # then there can't be any special characters. See RFC 2109.
248 if len(str) < 2:
249 return str
250 if str[0] != '"' or str[-1] != '"':
251 return str
252
253 # We have to assume that we must decode this string.
254 # Down to work.
255
256 # Remove the "s
257 str = str[1:-1]
Fred Drakeff5364a2000-08-24 14:40:35 +0000258
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000259 # Check for special sequences. Examples:
260 # \012 --> \n
261 # \" --> "
262 #
263 i = 0
264 n = len(str)
265 res = []
266 while 0 <= i < n:
267 Omatch = _OctalPatt.search(str, i)
268 Qmatch = _QuotePatt.search(str, i)
269 if not Omatch and not Qmatch: # Neither matched
270 res.append(str[i:])
271 break
272 # else:
273 j = k = -1
274 if Omatch: j = Omatch.start(0)
275 if Qmatch: k = Qmatch.start(0)
276 if Qmatch and ( not Omatch or k < j ): # QuotePatt matched
277 res.append(str[i:k])
278 res.append(str[k+1])
279 i = k+2
280 else: # OctalPatt matched
281 res.append(str[i:j])
Fred Draked451ec12002-04-26 02:29:55 +0000282 res.append( chr( int(str[j+1:j+4], 8) ) )
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000283 i = j+4
Fred Draked451ec12002-04-26 02:29:55 +0000284 return _nulljoin(res)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000285# end _unquote
286
287# The _getdate() routine is used to set the expiration time in
288# the cookie's HTTP header. By default, _getdate() returns the
Tim Peters88869f92001-01-14 23:36:06 +0000289# current time in the appropriate "expires" format for a
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000290# Set-Cookie header. The one optional argument is an offset from
291# now, in seconds. For example, an offset of -3600 means "one hour ago".
292# The offset may be a floating point number.
293#
294
295_weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
296
297_monthname = [None,
298 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
299 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
300
301def _getdate(future=0, weekdayname=_weekdayname, monthname=_monthname):
302 from time import gmtime, time
303 now = time()
304 year, month, day, hh, mm, ss, wd, y, z = gmtime(now + future)
305 return "%s, %02d-%3s-%4d %02d:%02d:%02d GMT" % \
306 (weekdayname[wd], day, monthname[month], year, hh, mm, ss)
307
308
309#
310# A class to hold ONE key,value pair.
311# In a cookie, each such pair may have several attributes.
312# so this class is used to keep the attributes associated
313# with the appropriate key,value pair.
314# This class also includes a coded_value attribute, which
315# is used to hold the network representation of the
316# value. This is most useful when Python objects are
317# pickled for network transit.
318#
319
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000320class Morsel(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000321 # RFC 2109 lists these attributes as reserved:
322 # path comment domain
323 # max-age secure version
Tim Peters88869f92001-01-14 23:36:06 +0000324 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000325 # For historical reasons, these attributes are also reserved:
326 # expires
327 #
Benjamin Peterson35e661c2008-09-06 19:37:35 +0000328 # This is an extension from Microsoft:
329 # httponly
330 #
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000331 # This dictionary provides a mapping from the lowercase
332 # variant on the left to the appropriate traditional
333 # formatting on the right.
334 _reserved = { "expires" : "expires",
335 "path" : "Path",
336 "comment" : "Comment",
337 "domain" : "Domain",
338 "max-age" : "Max-Age",
339 "secure" : "secure",
Benjamin Peterson35e661c2008-09-06 19:37:35 +0000340 "httponly" : "httponly",
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000341 "version" : "Version",
342 }
Fred Drakeff5364a2000-08-24 14:40:35 +0000343
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000344 def __init__(self):
345 # Set defaults
346 self.key = self.value = self.coded_value = None
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000347
348 # Set default attributes
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000349 for K in self._reserved:
350 dict.__setitem__(self, K, "")
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000351 # end __init__
352
353 def __setitem__(self, K, V):
Fred Draked451ec12002-04-26 02:29:55 +0000354 K = K.lower()
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000355 if not K in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000356 raise CookieError("Invalid Attribute %s" % K)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000357 dict.__setitem__(self, K, V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000358 # end __setitem__
359
360 def isReservedKey(self, K):
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000361 return K.lower() in self._reserved
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000362 # end isReservedKey
363
Walter Dörwald3f1e65c2007-06-08 15:33:46 +0000364 def set(self, key, val, coded_val, LegalChars=_LegalChars):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000365 # First we verify that the key isn't a reserved word
366 # Second we make sure it only contains legal characters
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000367 if key.lower() in self._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000368 raise CookieError("Attempt to set a reserved key: %s" % key)
Guido van Rossum0c41e882007-07-03 16:46:40 +0000369 if any(c not in LegalChars for c in key):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000370 raise CookieError("Illegal key value: %s" % key)
371
372 # It's a good key, so save it.
373 self.key = key
374 self.value = val
375 self.coded_value = coded_val
376 # end set
377
378 def output(self, attrs=None, header = "Set-Cookie:"):
379 return "%s %s" % ( header, self.OutputString(attrs) )
380
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000381 __str__ = output
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000382
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000383 def __repr__(self):
384 return '<%s: %s=%s>' % (self.__class__.__name__,
385 self.key, repr(self.value) )
Fred Drakeff5364a2000-08-24 14:40:35 +0000386
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000387 def js_output(self, attrs=None):
388 # Print javascript
389 return """
Georg Brandl03a33ea2005-06-26 21:02:49 +0000390 <script type="text/javascript">
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000391 <!-- begin hiding
Georg Brandl03a33ea2005-06-26 21:02:49 +0000392 document.cookie = \"%s\";
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000393 // end hiding -->
394 </script>
Senthil Kumaran3e2ea792009-04-02 03:02:03 +0000395 """ % ( self.OutputString(attrs).replace('"',r'\"'))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000396 # end js_output()
397
398 def OutputString(self, attrs=None):
399 # Build up our result
400 #
401 result = []
402 RA = result.append
Fred Drakeff5364a2000-08-24 14:40:35 +0000403
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000404 # First, the key=value pair
Georg Brandl532efab2005-08-24 22:34:21 +0000405 RA("%s=%s" % (self.key, self.coded_value))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000406
407 # Now add any defined attributes
Fred Drake8152d322000-12-12 23:20:45 +0000408 if attrs is None:
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000409 attrs = self._reserved
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000410 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000411 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000412 if V == "": continue
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000413 if K not in attrs: continue
414 if K == "expires" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000415 RA("%s=%s" % (self._reserved[K], _getdate(V)))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000416 elif K == "max-age" and type(V) == type(1):
Georg Brandl532efab2005-08-24 22:34:21 +0000417 RA("%s=%d" % (self._reserved[K], V))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000418 elif K == "secure":
Georg Brandl532efab2005-08-24 22:34:21 +0000419 RA(str(self._reserved[K]))
Benjamin Peterson35e661c2008-09-06 19:37:35 +0000420 elif K == "httponly":
421 RA(str(self._reserved[K]))
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000422 else:
Georg Brandl532efab2005-08-24 22:34:21 +0000423 RA("%s=%s" % (self._reserved[K], V))
Fred Drakeff5364a2000-08-24 14:40:35 +0000424
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000425 # Return the result
Georg Brandl532efab2005-08-24 22:34:21 +0000426 return _semispacejoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000427 # end OutputString
428# end Morsel class
429
430
431
432#
433# Pattern for finding cookie
434#
435# This used to be strict parsing based on the RFC2109 and RFC2068
436# specifications. I have since discovered that MSIE 3.0x doesn't
437# follow the character rules outlined in those specs. As a
438# result, the parsing rules here are less strict.
439#
440
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000441_LegalCharsPatt = r"[\w\d!#%&'~_`><@,:/\$\*\+\-\.\^\|\)\(\?\}\{\=]"
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000442_CookiePattern = re.compile(
443 r"(?x)" # This is a Verbose pattern
444 r"(?P<key>" # Start of group 'key'
Andrew M. Kuchlingc05abb32001-02-20 22:11:24 +0000445 ""+ _LegalCharsPatt +"+?" # Any word of at least one letter, nongreedy
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000446 r")" # End of group 'key'
447 r"\s*=\s*" # Equal Sign
448 r"(?P<val>" # Start of group 'val'
449 r'"(?:[^\\"]|\\.)*"' # Any doublequoted string
450 r"|" # or
451 ""+ _LegalCharsPatt +"*" # Any word or empty string
452 r")" # End of group 'val'
453 r"\s*;?" # Probably ending in a semi-colon
Antoine Pitroufd036452008-08-19 17:56:33 +0000454 , re.ASCII) # May be removed if safe.
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000455
456
457# At long last, here is the cookie class.
458# Using this class is almost just like using a dictionary.
459# See this module's docstring for example usage.
460#
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000461class BaseCookie(dict):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000462 # A container class for a set of Morsels
463 #
Fred Drakeff5364a2000-08-24 14:40:35 +0000464
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000465 def value_decode(self, val):
466 """real_value, coded_value = value_decode(STRING)
467 Called prior to setting a cookie's value from the network
468 representation. The VALUE is the value read from HTTP
469 header.
470 Override this function to modify the behavior of cookies.
471 """
472 return val, val
473 # end value_encode
474
475 def value_encode(self, val):
476 """real_value, coded_value = value_encode(VALUE)
477 Called prior to setting a cookie's value from the dictionary
478 representation. The VALUE is the value being assigned.
479 Override this function to modify the behavior of cookies.
480 """
481 strval = str(val)
482 return strval, strval
483 # end value_encode
Fred Drakeff5364a2000-08-24 14:40:35 +0000484
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000485 def __init__(self, input=None):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000486 if input: self.load(input)
487 # end __init__
488
489 def __set(self, key, real_value, coded_value):
490 """Private method for setting a cookie's value"""
491 M = self.get(key, Morsel())
492 M.set(key, real_value, coded_value)
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000493 dict.__setitem__(self, key, M)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000494 # end __set
495
496 def __setitem__(self, key, value):
497 """Dictionary style assignment."""
498 rval, cval = self.value_encode(value)
499 self.__set(key, rval, cval)
500 # end __setitem__
501
Georg Brandl532efab2005-08-24 22:34:21 +0000502 def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000503 """Return a string suitable for HTTP."""
504 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000505 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000506 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000507 result.append( V.output(attrs, header) )
Fred Draked451ec12002-04-26 02:29:55 +0000508 return sep.join(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000509 # end output
510
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000511 __str__ = output
512
513 def __repr__(self):
514 L = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000515 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000516 for K,V in items:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000517 L.append( '%s=%s' % (K,repr(V.value) ) )
Georg Brandl8246c432005-08-25 07:32:42 +0000518 return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
Fred Drakeff5364a2000-08-24 14:40:35 +0000519
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000520 def js_output(self, attrs=None):
521 """Return a string suitable for JavaScript."""
522 result = []
Guido van Rossumcc2b0162007-02-11 06:12:03 +0000523 items = sorted(self.items())
Tim Peters2f228e72001-05-13 00:19:31 +0000524 for K,V in items:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000525 result.append( V.js_output(attrs) )
Fred Draked451ec12002-04-26 02:29:55 +0000526 return _nulljoin(result)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000527 # end js_output
528
529 def load(self, rawdata):
530 """Load cookies from a string (presumably HTTP_COOKIE) or
531 from a dictionary. Loading cookies from a dictionary 'd'
532 is equivalent to calling:
533 map(Cookie.__setitem__, d.keys(), d.values())
534 """
535 if type(rawdata) == type(""):
536 self.__ParseString(rawdata)
537 else:
538 self.update(rawdata)
539 return
540 # end load()
Fred Drakeff5364a2000-08-24 14:40:35 +0000541
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000542 def __ParseString(self, str, patt=_CookiePattern):
543 i = 0 # Our starting point
544 n = len(str) # Length of string
545 M = None # current morsel
546
547 while 0 <= i < n:
548 # Start looking for a cookie
549 match = patt.search(str, i)
550 if not match: break # No more cookies
551
552 K,V = match.group("key"), match.group("val")
553 i = match.end(0)
554
555 # Parse the key, value in case it's metainfo
556 if K[0] == "$":
557 # We ignore attributes which pertain to the cookie
558 # mechanism as a whole. See RFC 2109.
559 # (Does anyone care?)
560 if M:
561 M[ K[1:] ] = V
Raymond Hettinger0a2963c2002-06-26 15:19:01 +0000562 elif K.lower() in Morsel._reserved:
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000563 if M:
Andrew M. Kuchling0b29b112000-08-24 11:52:33 +0000564 M[ K ] = _unquote(V)
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000565 else:
566 rval, cval = self.value_decode(V)
567 self.__set(K, rval, cval)
568 M = self[K]
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000569 # end __ParseString
570# end BaseCookie class
571
572class SimpleCookie(BaseCookie):
573 """SimpleCookie
574 SimpleCookie supports strings as cookie values. When setting
575 the value using the dictionary assignment notation, SimpleCookie
576 calls the builtin str() to convert the value to a string. Values
577 received from HTTP are kept as strings.
578 """
579 def value_decode(self, val):
580 return _unquote( val ), val
581 def value_encode(self, val):
582 strval = str(val)
583 return strval, _quote( strval )
584# end SimpleCookie
585
Andrew M. Kuchling52ea8722000-08-19 13:01:19 +0000586#
587###########################################################
588
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000589def _test():
Georg Brandl24420152008-05-26 16:32:26 +0000590 import doctest, http.cookies
591 return doctest.testmod(http.cookies)
Guido van Rossum58b6f5b2001-04-06 19:39:11 +0000592
593if __name__ == "__main__":
594 _test()