patch #848017: make Cookie more RFC-compliant.

This commit is contained in:
Georg Brandl 2005-08-24 22:34:21 +00:00
parent e1b13d2019
commit 532efabf1d
3 changed files with 45 additions and 45 deletions

View File

@ -98,7 +98,9 @@ In general, it should be the case that \method{value_encode()} and
Return a string representation suitable to be sent as HTTP headers.
\var{attrs} and \var{header} are sent to each \class{Morsel}'s
\method{output()} method. \var{sep} is used to join the headers
together, and is by default a newline.
together, and is by default the combination '\r\n' (CRLF).
\versionchanged[The default separator has been changed from '\n' to match the cookie
specification]{2.5}
\end{methoddesc}
\begin{methoddesc}[BaseCookie]{js_output}{\optional{attrs}}
@ -195,32 +197,32 @@ The following example demonstrates how to use the \module{Cookie} module.
>>> C["fig"] = "newton"
>>> C["sugar"] = "wafer"
>>> print C # generate HTTP headers
Set-Cookie: sugar=wafer;
Set-Cookie: fig=newton;
Set-Cookie: sugar=wafer
Set-Cookie: fig=newton
>>> print C.output() # same thing
Set-Cookie: sugar=wafer;
Set-Cookie: fig=newton;
Set-Cookie: sugar=wafer
Set-Cookie: fig=newton
>>> C = Cookie.SmartCookie()
>>> C["rocky"] = "road"
>>> C["rocky"]["path"] = "/cookie"
>>> print C.output(header="Cookie:")
Cookie: rocky=road; Path=/cookie;
Cookie: rocky=road; Path=/cookie
>>> print C.output(attrs=[], header="Cookie:")
Cookie: rocky=road;
Cookie: rocky=road
>>> C = Cookie.SmartCookie()
>>> C.load("chips=ahoy; vienna=finger") # load from a string (HTTP header)
>>> print C
Set-Cookie: vienna=finger;
Set-Cookie: chips=ahoy;
Set-Cookie: vienna=finger
Set-Cookie: chips=ahoy
>>> C = Cookie.SmartCookie()
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
>>> print C
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;";
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
>>> C = Cookie.SmartCookie()
>>> C["oreo"] = "doublestuff"
>>> C["oreo"]["path"] = "/"
>>> print C
Set-Cookie: oreo=doublestuff; Path=/;
Set-Cookie: oreo=doublestuff; Path=/
>>> C = Cookie.SmartCookie()
>>> C["twix"] = "none for you"
>>> C["twix"].value
@ -233,8 +235,8 @@ Set-Cookie: oreo=doublestuff; Path=/;
>>> C["string"].value
'seven'
>>> print C
Set-Cookie: number=7;
Set-Cookie: string=seven;
Set-Cookie: number=7
Set-Cookie: string=seven
>>> C = Cookie.SerialCookie()
>>> C["number"] = 7
>>> C["string"] = "seven"
@ -243,8 +245,8 @@ Set-Cookie: string=seven;
>>> C["string"].value
'seven'
>>> print C
Set-Cookie: number="I7\012.";
Set-Cookie: string="S'seven'\012p1\012.";
Set-Cookie: number="I7\012."
Set-Cookie: string="S'seven'\012p1\012."
>>> C = Cookie.SmartCookie()
>>> C["number"] = 7
>>> C["string"] = "seven"
@ -253,6 +255,6 @@ Set-Cookie: string="S'seven'\012p1\012.";
>>> C["string"].value
'seven'
>>> print C
Set-Cookie: number="I7\012.";
Set-Cookie: string=seven;
Set-Cookie: number="I7\012."
Set-Cookie: string=seven
\end{verbatim}

View File

@ -69,9 +69,8 @@ a dictionary.
>>> C = Cookie.SmartCookie()
>>> C["fig"] = "newton"
>>> C["sugar"] = "wafer"
>>> print C
Set-Cookie: fig=newton;
Set-Cookie: sugar=wafer;
>>> C.output()
'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer'
Notice that the printable representation of a Cookie is the
appropriate format for a Set-Cookie: header. This is the
@ -82,9 +81,9 @@ attributes by using the .output() function
>>> C["rocky"] = "road"
>>> C["rocky"]["path"] = "/cookie"
>>> print C.output(header="Cookie:")
Cookie: rocky=road; Path=/cookie;
Cookie: rocky=road; Path=/cookie
>>> print C.output(attrs=[], header="Cookie:")
Cookie: rocky=road;
Cookie: rocky=road
The load() method of a Cookie extracts cookies from a string. In a
CGI script, you would use this method to extract the cookies from the
@ -92,9 +91,8 @@ HTTP_COOKIE environment variable.
>>> C = Cookie.SmartCookie()
>>> C.load("chips=ahoy; vienna=finger")
>>> print C
Set-Cookie: chips=ahoy;
Set-Cookie: vienna=finger;
>>> C.output()
'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger'
The load() method is darn-tootin smart about identifying cookies
within a string. Escaped quotation marks, nested semicolons, and other
@ -103,7 +101,7 @@ such trickeries do not confuse it.
>>> C = Cookie.SmartCookie()
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
>>> print C
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;";
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Each element of the Cookie also supports all of the RFC 2109
Cookie attributes. Here's an example which sets the Path
@ -113,7 +111,7 @@ attribute.
>>> C["oreo"] = "doublestuff"
>>> C["oreo"]["path"] = "/"
>>> print C
Set-Cookie: oreo=doublestuff; Path=/;
Set-Cookie: oreo=doublestuff; Path=/
Each dictionary element has a 'value' attribute, which gives you
back the value associated with the key.
@ -144,9 +142,8 @@ the value to a string, when the values are set dictionary-style.
'7'
>>> C["string"].value
'seven'
>>> print C
Set-Cookie: number=7;
Set-Cookie: string=seven;
>>> C.output()
'Set-Cookie: number=7\r\nSet-Cookie: string=seven'
SerialCookie
@ -165,9 +162,8 @@ values, however.)
7
>>> C["string"].value
'seven'
>>> print C
Set-Cookie: number="I7\012.";
Set-Cookie: string="S'seven'\012p1\012.";
>>> C.output()
'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."'
Be warned, however, if SerialCookie cannot de-serialize a value (because
it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION.
@ -190,9 +186,8 @@ as a string.
7
>>> C["string"].value
'seven'
>>> print C
Set-Cookie: number="I7\012.";
Set-Cookie: string=seven;
>>> C.output()
'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven'
Backwards Compatibility
@ -228,7 +223,7 @@ __all__ = ["CookieError","BaseCookie","SimpleCookie","SerialCookie",
"SmartCookie","Cookie"]
_nulljoin = ''.join
_spacejoin = ' '.join
_semispacejoin = '; '.join
#
# Define an exception visible to External modules
@ -485,7 +480,7 @@ class Morsel(dict):
RA = result.append
# First, the key=value pair
RA("%s=%s;" % (self.key, self.coded_value))
RA("%s=%s" % (self.key, self.coded_value))
# Now add any defined attributes
if attrs is None:
@ -496,16 +491,16 @@ class Morsel(dict):
if V == "": continue
if K not in attrs: continue
if K == "expires" and type(V) == type(1):
RA("%s=%s;" % (self._reserved[K], _getdate(V)))
RA("%s=%s" % (self._reserved[K], _getdate(V)))
elif K == "max-age" and type(V) == type(1):
RA("%s=%d;" % (self._reserved[K], V))
RA("%s=%d" % (self._reserved[K], V))
elif K == "secure":
RA("%s;" % self._reserved[K])
RA(str(self._reserved[K]))
else:
RA("%s=%s;" % (self._reserved[K], V))
RA("%s=%s" % (self._reserved[K], V))
# Return the result
return _spacejoin(result)
return _semispacejoin(result)
# end OutputString
# end Morsel class
@ -581,7 +576,7 @@ class BaseCookie(dict):
self.__set(key, rval, cval)
# end __setitem__
def output(self, attrs=None, header="Set-Cookie:", sep="\n"):
def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
"""Return a string suitable for HTTP."""
result = []
items = self.items()
@ -599,7 +594,7 @@ class BaseCookie(dict):
items.sort()
for K,V in items:
L.append( '%s=%s' % (K,repr(V.value) ) )
return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L))
return '<%s: %s>' % (self.__class__.__name__, _semispacejoin(L))
def js_output(self, attrs=None):
"""Return a string suitable for JavaScript."""

View File

@ -193,6 +193,9 @@ Extension Modules
Library
-------
- Patch #848017: Make Cookie more RFC-compliant. Use CRLF as default output
separator and do not output trailing semicola.
- Patch #1062060: urllib.urlretrieve() now raises a new exception, named
ContentTooShortException, when the actually downloaded size does not
match the Content-Length header.