Fixed #28965 -- Updated Set-Cookie's Expires date format to follow RFC 7231.

This commit is contained in:
Alexey 2017-12-28 00:49:46 +03:00 committed by Tim Graham
parent 5f456408a0
commit 0afffae4ec
6 changed files with 20 additions and 15 deletions

View File

@ -6,7 +6,7 @@ from django.contrib.sessions.backends.base import UpdateError
from django.core.exceptions import SuspiciousOperation from django.core.exceptions import SuspiciousOperation
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.deprecation import MiddlewareMixin from django.utils.deprecation import MiddlewareMixin
from django.utils.http import cookie_date from django.utils.http import http_date
class SessionMiddleware(MiddlewareMixin): class SessionMiddleware(MiddlewareMixin):
@ -50,7 +50,7 @@ class SessionMiddleware(MiddlewareMixin):
else: else:
max_age = request.session.get_expiry_age() max_age = request.session.get_expiry_age()
expires_time = time.time() + max_age expires_time = time.time() + max_age
expires = cookie_date(expires_time) expires = http_date(expires_time)
# Save the session data and refresh the client cookie. # Save the session data and refresh the client cookie.
# Skip session save for 500 responses, refs #3881. # Skip session save for 500 responses, refs #3881.
if response.status_code != 500: if response.status_code != 500:

View File

@ -14,7 +14,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.http.cookie import SimpleCookie from django.http.cookie import SimpleCookie
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_bytes, iri_to_uri from django.utils.encoding import force_bytes, iri_to_uri
from django.utils.http import cookie_date from django.utils.http import http_date
_charset_from_content_type_re = re.compile(r';\s*charset=(?P<charset>[^\s;]+)', re.I) _charset_from_content_type_re = re.compile(r';\s*charset=(?P<charset>[^\s;]+)', re.I)
@ -185,8 +185,7 @@ class HttpResponseBase:
self.cookies[key]['max-age'] = max_age self.cookies[key]['max-age'] = max_age
# IE requires expires, so set it if hasn't been already. # IE requires expires, so set it if hasn't been already.
if not expires: if not expires:
self.cookies[key]['expires'] = cookie_date(time.time() + self.cookies[key]['expires'] = http_date(time.time() + max_age)
max_age)
if path is not None: if path is not None:
self.cookies[key]['path'] = path self.cookies[key]['path'] = path
if domain is not None: if domain is not None:
@ -207,7 +206,7 @@ class HttpResponseBase:
def delete_cookie(self, key, path='/', domain=None): def delete_cookie(self, key, path='/', domain=None):
self.set_cookie(key, max_age=0, path=path, domain=domain, self.set_cookie(key, max_age=0, path=path, domain=domain,
expires='Thu, 01-Jan-1970 00:00:00 GMT') expires='Thu, 01 Jan 1970 00:00:00 GMT')
# Common methods used by subclasses # Common methods used by subclasses

View File

@ -232,6 +232,12 @@ Miscellaneous
* The minimum supported version of ``mysqlclient`` is increased from 1.3.3 to * The minimum supported version of ``mysqlclient`` is increased from 1.3.3 to
1.3.7. 1.3.7.
* The date format of ``Set-Cookie``'s ``Expires`` directive is changed to
follow :rfc:`7231#section-7.1.1.1` instead of Netscape's cookie standard.
Hyphens present in dates like ``Tue, 25-Dec-2018 22:26:13 GMT`` are removed.
This change should be merely cosmetic except perhaps for antiquated browsers
that don't parse the new format.
.. _deprecated-features-2.1: .. _deprecated-features-2.1:
Features deprecated in 2.1 Features deprecated in 2.1

View File

@ -82,7 +82,7 @@ class CookieTests(BaseTests, SimpleTestCase):
storage.update(response) storage.update(response)
self.assertEqual(response.cookies['messages'].value, '') self.assertEqual(response.cookies['messages'].value, '')
self.assertEqual(response.cookies['messages']['domain'], '.example.com') self.assertEqual(response.cookies['messages']['domain'], '.example.com')
self.assertEqual(response.cookies['messages']['expires'], 'Thu, 01-Jan-1970 00:00:00 GMT') self.assertEqual(response.cookies['messages']['expires'], 'Thu, 01 Jan 1970 00:00:00 GMT')
def test_get_bad_cookie(self): def test_get_bad_cookie(self):
request = self.get_request() request = self.get_request()

View File

@ -14,7 +14,7 @@ from django.http.request import split_domain_port
from django.test import RequestFactory, SimpleTestCase, override_settings from django.test import RequestFactory, SimpleTestCase, override_settings
from django.test.client import FakePayload from django.test.client import FakePayload
from django.test.utils import freeze_time from django.test.utils import freeze_time
from django.utils.http import cookie_date from django.utils.http import http_date
from django.utils.timezone import utc from django.utils.timezone import utc
@ -234,7 +234,7 @@ class RequestsTests(SimpleTestCase):
response.set_cookie('c', 'old-value') response.set_cookie('c', 'old-value')
self.assertEqual(response.cookies['c']['expires'], '') self.assertEqual(response.cookies['c']['expires'], '')
response.delete_cookie('c') response.delete_cookie('c')
self.assertEqual(response.cookies['c']['expires'], 'Thu, 01-Jan-1970 00:00:00 GMT') self.assertEqual(response.cookies['c']['expires'], 'Thu, 01 Jan 1970 00:00:00 GMT')
response.set_cookie('c', 'new-value') response.set_cookie('c', 'new-value')
self.assertEqual(response.cookies['c']['expires'], '') self.assertEqual(response.cookies['c']['expires'], '')
@ -246,7 +246,7 @@ class RequestsTests(SimpleTestCase):
self.assertIn( self.assertIn(
datetime_cookie['expires'], datetime_cookie['expires'],
# assertIn accounts for slight time dependency (#23450) # assertIn accounts for slight time dependency (#23450)
('Sat, 01-Jan-2028 04:05:06 GMT', 'Sat, 01-Jan-2028 04:05:07 GMT') ('Sat, 01 Jan 2028 04:05:06 GMT', 'Sat, 01 Jan 2028 04:05:07 GMT')
) )
def test_max_age_expiration(self): def test_max_age_expiration(self):
@ -257,7 +257,7 @@ class RequestsTests(SimpleTestCase):
response.set_cookie('max_age', max_age=10) response.set_cookie('max_age', max_age=10)
max_age_cookie = response.cookies['max_age'] max_age_cookie = response.cookies['max_age']
self.assertEqual(max_age_cookie['max-age'], 10) self.assertEqual(max_age_cookie['max-age'], 10)
self.assertEqual(max_age_cookie['expires'], cookie_date(set_cookie_time + 10)) self.assertEqual(max_age_cookie['expires'], http_date(set_cookie_time + 10))
def test_httponly_cookie(self): def test_httponly_cookie(self):
response = HttpResponse() response = HttpResponse()

View File

@ -730,9 +730,9 @@ class SessionMiddlewareTests(TestCase):
# The cookie was deleted, not recreated. # The cookie was deleted, not recreated.
# A deleted cookie header looks like: # A deleted cookie header looks like:
# Set-Cookie: sessionid=; expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; Path=/ # Set-Cookie: sessionid=; expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0; Path=/
self.assertEqual( self.assertEqual(
'Set-Cookie: {}=""; expires=Thu, 01-Jan-1970 00:00:00 GMT; ' 'Set-Cookie: {}=""; expires=Thu, 01 Jan 1970 00:00:00 GMT; '
'Max-Age=0; Path=/'.format( 'Max-Age=0; Path=/'.format(
settings.SESSION_COOKIE_NAME, settings.SESSION_COOKIE_NAME,
), ),
@ -758,11 +758,11 @@ class SessionMiddlewareTests(TestCase):
# The cookie was deleted, not recreated. # The cookie was deleted, not recreated.
# A deleted cookie header with a custom domain and path looks like: # A deleted cookie header with a custom domain and path looks like:
# Set-Cookie: sessionid=; Domain=.example.local; # Set-Cookie: sessionid=; Domain=.example.local;
# expires=Thu, 01-Jan-1970 00:00:00 GMT; Max-Age=0; # expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0;
# Path=/example/ # Path=/example/
self.assertEqual( self.assertEqual(
'Set-Cookie: {}=""; Domain=.example.local; expires=Thu, ' 'Set-Cookie: {}=""; Domain=.example.local; expires=Thu, '
'01-Jan-1970 00:00:00 GMT; Max-Age=0; Path=/example/'.format( '01 Jan 1970 00:00:00 GMT; Max-Age=0; Path=/example/'.format(
settings.SESSION_COOKIE_NAME, settings.SESSION_COOKIE_NAME,
), ),
str(response.cookies[settings.SESSION_COOKIE_NAME]) str(response.cookies[settings.SESSION_COOKIE_NAME])