Fixed #5816 -- Fixed a regression from [6333] that generates incorrect cookie "expires" dates when using a locale other than English. Introduced `http_date` and `cookie_date` utility functions. Thanks for the report Michael Lemaire. Thanks for the patch Karen Tracey and `SmileyChris`.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@6634 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Gary Wilson Jr 2007-10-31 03:59:40 +00:00
parent 39f28512b9
commit 8c442f21dc
7 changed files with 51 additions and 21 deletions

View File

@ -1,9 +1,8 @@
import time import time
import datetime
from email.Utils import formatdate
from django.conf import settings from django.conf import settings
from django.utils.cache import patch_vary_headers from django.utils.cache import patch_vary_headers
from django.utils.http import cookie_date
TEST_COOKIE_NAME = 'testcookie' TEST_COOKIE_NAME = 'testcookie'
TEST_COOKIE_VALUE = 'worked' TEST_COOKIE_VALUE = 'worked'
@ -32,13 +31,8 @@ class SessionMiddleware(object):
expires = None expires = None
else: else:
max_age = settings.SESSION_COOKIE_AGE max_age = settings.SESSION_COOKIE_AGE
rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE) expires_time = time.time() + settings.SESSION_COOKIE_AGE
expires = cookie_date(expires_time)
# Fixed length date must have '-' separation in the format
# DD-MMM-YYYY for compliance with Netscape cookie standard
expires = datetime.datetime.strftime(datetime.datetime.utcnow() + \
datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE), "%a, %d-%b-%Y %H:%M:%S GMT")
# Save the seesion data and refresh the client cookie. # Save the seesion data and refresh the client cookie.
request.session.save() request.session.save()
response.set_cookie(settings.SESSION_COOKIE_NAME, response.set_cookie(settings.SESSION_COOKIE_NAME,

View File

@ -9,14 +9,14 @@ been reviewed for security issues. Don't use it for production use.
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from types import ListType, StringType from types import ListType, StringType
from email.Utils import formatdate
import mimetypes import mimetypes
import os import os
import re import re
import sys import sys
import time
import urllib import urllib
from django.utils.http import http_date
__version__ = "0.1" __version__ = "0.1"
__all__ = ['WSGIServer','WSGIRequestHandler','demo_app'] __all__ = ['WSGIServer','WSGIRequestHandler','demo_app']
@ -376,7 +376,7 @@ class ServerHandler(object):
self._write('HTTP/%s %s\r\n' % (self.http_version,self.status)) self._write('HTTP/%s %s\r\n' % (self.http_version,self.status))
if 'Date' not in self.headers: if 'Date' not in self.headers:
self._write( self._write(
'Date: %s\r\n' % (formatdate()[:26] + "GMT") 'Date: %s\r\n' % http_date()
) )
if self.server_software and 'Server' not in self.headers: if self.server_software and 'Server' not in self.headers:
self._write('Server: %s\r\n' % self.server_software) self._write('Server: %s\r\n' % self.server_software)

View File

@ -1,4 +1,4 @@
from email.Utils import formatdate from django.utils.http import http_date
class ConditionalGetMiddleware(object): class ConditionalGetMiddleware(object):
""" """
@ -11,7 +11,7 @@ class ConditionalGetMiddleware(object):
Also sets the Date and Content-Length response-headers. Also sets the Date and Content-Length response-headers.
""" """
def process_response(self, request, response): def process_response(self, request, response):
response['Date'] = formatdate()[:26] + "GMT" response['Date'] = http_date()
if not response.has_header('Content-Length'): if not response.has_header('Content-Length'):
response['Content-Length'] = str(len(response.content)) response['Content-Length'] = str(len(response.content))

View File

@ -20,11 +20,11 @@ An example: i18n middleware would need to distinguish caches by the
import md5 import md5
import re import re
import time import time
from email.Utils import formatdate
from django.conf import settings from django.conf import settings
from django.core.cache import cache from django.core.cache import cache
from django.utils.encoding import smart_str, iri_to_uri from django.utils.encoding import smart_str, iri_to_uri
from django.utils.http import http_date
cc_delim_re = re.compile(r'\s*,\s*') cc_delim_re = re.compile(r'\s*,\s*')
@ -89,9 +89,9 @@ def patch_response_headers(response, cache_timeout=None):
if not response.has_header('ETag'): if not response.has_header('ETag'):
response['ETag'] = md5.new(response.content).hexdigest() response['ETag'] = md5.new(response.content).hexdigest()
if not response.has_header('Last-Modified'): if not response.has_header('Last-Modified'):
response['Last-Modified'] = formatdate()[:26] + "GMT" response['Last-Modified'] = http_date()
if not response.has_header('Expires'): if not response.has_header('Expires'):
response['Expires'] = formatdate(time.time() + cache_timeout)[:26] + "GMT" response['Expires'] = http_date(time.time() + cache_timeout)
patch_cache_control(response, max_age=cache_timeout) patch_cache_control(response, max_age=cache_timeout)
def add_never_cache_headers(response): def add_never_cache_headers(response):

View File

@ -1,4 +1,6 @@
import urllib import urllib
from email.Utils import formatdate
from django.utils.encoding import smart_str, force_unicode from django.utils.encoding import smart_str, force_unicode
from django.utils.functional import allow_lazy from django.utils.functional import allow_lazy
@ -37,3 +39,29 @@ def urlencode(query, doseq=0):
for k, v in query], for k, v in query],
doseq) doseq)
def cookie_date(epoch_seconds=None):
"""
Formats the time to ensure compatibility with Netscape's cookie standard.
Accepts a floating point number expressed in seconds since the epoch, in
UTC - such as that outputted by time.time(). If set to None, defaults to
the current time.
Outputs a string in the format 'Wdy, DD-Mon-YYYY HH:MM:SS GMT'.
"""
rfcdate = formatdate(epoch_seconds)
return '%s-%s-%s GMT' % (rfcdate[:7], rfcdate[8:11], rfcdate[12:25])
def http_date(epoch_seconds=None):
"""
Formats the time to match the RFC1123 date format as specified by HTTP
RFC2616 section 3.3.1.
Accepts a floating point number expressed in seconds since the epoch, in
UTC - such as that outputted by time.time(). If set to None, defaults to
the current time.
Outputs a string in the format 'Wdy, DD Mon YYYY HH:MM:SS GMT'.
"""
rfcdate = formatdate(epoch_seconds)
return '%s GMT' % rfcdate[:25]

View File

@ -7,13 +7,14 @@ import mimetypes
import os import os
import posixpath import posixpath
import re import re
import rfc822
import stat import stat
import urllib import urllib
from email.Utils import parsedate_tz, mktime_tz
from django.template import loader from django.template import loader
from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified
from django.template import Template, Context, TemplateDoesNotExist from django.template import Template, Context, TemplateDoesNotExist
from django.utils.http import http_date
def serve(request, path, document_root=None, show_indexes=False): def serve(request, path, document_root=None, show_indexes=False):
""" """
@ -60,7 +61,7 @@ def serve(request, path, document_root=None, show_indexes=False):
mimetype = mimetypes.guess_type(fullpath)[0] mimetype = mimetypes.guess_type(fullpath)[0]
contents = open(fullpath, 'rb').read() contents = open(fullpath, 'rb').read()
response = HttpResponse(contents, mimetype=mimetype) response = HttpResponse(contents, mimetype=mimetype)
response["Last-Modified"] = rfc822.formatdate(statobj[stat.ST_MTIME]) response["Last-Modified"] = http_date(statobj[stat.ST_MTIME])
return response return response
DEFAULT_DIRECTORY_INDEX_TEMPLATE = """ DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
@ -119,8 +120,7 @@ def was_modified_since(header=None, mtime=0, size=0):
raise ValueError raise ValueError
matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header, matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header,
re.IGNORECASE) re.IGNORECASE)
header_mtime = rfc822.mktime_tz(rfc822.parsedate_tz( header_mtime = mktime_tz(parsedate_tz(matches.group(1)))
matches.group(1)))
header_len = matches.group(3) header_len = matches.group(3)
if header_len and int(header_len) != size: if header_len and int(header_len) != size:
raise ValueError raise ValueError

View File

@ -27,6 +27,14 @@ u'Paris+%26+Orl%C3%A9ans'
>>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&") >>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&")
u'Paris+&+Orl%C3%A9ans' u'Paris+&+Orl%C3%A9ans'
### cookie_date, http_date ###############################################
>>> from django.utils.http import cookie_date, http_date
>>> t = 1167616461.0
>>> cookie_date(t)
'Mon, 01-Jan-2007 01:54:21 GMT'
>>> http_date(t)
'Mon, 01 Jan 2007 01:54:21 GMT'
### iri_to_uri ########################################################### ### iri_to_uri ###########################################################
>>> from django.utils.encoding import iri_to_uri >>> from django.utils.encoding import iri_to_uri
>>> iri_to_uri(u'red%09ros\xe9#red') >>> iri_to_uri(u'red%09ros\xe9#red')