feat(set_cookie): Convert max-age value to int implicitly (#711)
Make set_cookie() more robust in handling max-age values, without introducing significant overhead. Fixes #704
This commit is contained in:
committed by
Kurt Griffiths
parent
538958713b
commit
296e6430c5
1
AUTHORS
1
AUTHORS
@@ -60,6 +60,7 @@ below in order of date of first contribution:
|
||||
* Yohan Boniface (yohanboniface)
|
||||
* Steven Colby (StevenWColby)
|
||||
* M Somerville (dracos)
|
||||
* Jan-Philip Gehrcke (jgehrcke)
|
||||
* Abhilash Raj (maxking)
|
||||
* David Larlet (davidbgk)
|
||||
* Fran Fitzpatrick (fxfitz)
|
||||
|
||||
@@ -154,7 +154,8 @@ class Response(object):
|
||||
default, cookies expire when the user agent exits.
|
||||
max_age (int): Defines the lifetime of the cookie in seconds.
|
||||
After the specified number of seconds elapse, the client
|
||||
should discard the cookie.
|
||||
should discard the cookie. Coercion to `int` is attempted
|
||||
if provided with `float` or `str`.
|
||||
domain (str): Specifies the domain for which the cookie is valid.
|
||||
An explicitly specified domain must always start with a dot.
|
||||
A value of 0 means the cookie should be discarded immediately.
|
||||
@@ -218,7 +219,13 @@ class Response(object):
|
||||
self._cookies[name]['expires'] = gmt_expires.strftime(fmt)
|
||||
|
||||
if max_age:
|
||||
self._cookies[name]['max-age'] = max_age
|
||||
# RFC 6265 section 5.2.2 says about the max-age value:
|
||||
# "If the remainder of attribute-value contains a non-DIGIT
|
||||
# character, ignore the cookie-av."
|
||||
# That is, RFC-compliant response parsers will ignore the max-age
|
||||
# attribute if the value contains a dot, as in floating point
|
||||
# numbers. Therefore, attempt to convert the value to an integer.
|
||||
self._cookies[name]['max-age'] = int(max_age)
|
||||
|
||||
if domain:
|
||||
self._cookies[name]['domain'] = domain
|
||||
|
||||
@@ -50,6 +50,15 @@ class CookieResource:
|
||||
resp.unset_cookie('bad')
|
||||
|
||||
|
||||
class CookieResourceMaxAgeFloatString:
|
||||
|
||||
def on_get(self, req, resp):
|
||||
resp.set_cookie(
|
||||
'foofloat', 'bar', max_age=15.3, secure=False, http_only=False)
|
||||
resp.set_cookie(
|
||||
'foostring', 'bar', max_age='15', secure=False, http_only=False)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class TestCookies(testing.TestBase):
|
||||
|
||||
@@ -113,6 +122,17 @@ class TestCookies(testing.TestBase):
|
||||
self.assertEqual(morsel.value, 'bar')
|
||||
self.assertEqual(morsel['max-age'], 300)
|
||||
|
||||
def test_cookie_max_age_float_and_string(self):
|
||||
# Falcon implicitly converts max-age values to integers,
|
||||
# for ensuring RFC 6265-compliance of the attribute value.
|
||||
self.resource = CookieResourceMaxAgeFloatString()
|
||||
self.api.add_route(self.test_route, self.resource)
|
||||
self.simulate_request(self.test_route, method='GET')
|
||||
self.assertIn(
|
||||
('set-cookie', 'foofloat=bar; Max-Age=15'), self.srmock.headers)
|
||||
self.assertIn(
|
||||
('set-cookie', 'foostring=bar; Max-Age=15'), self.srmock.headers)
|
||||
|
||||
def test_response_unset_cookie(self):
|
||||
resp = falcon.Response()
|
||||
resp.unset_cookie('bad')
|
||||
|
||||
Reference in New Issue
Block a user