mirror of https://github.com/python/cpython
patch #848017: make Cookie more RFC-compliant.
This commit is contained in:
parent
e1b13d2019
commit
532efabf1d
|
@ -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}
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue