diff --git a/django/contrib/sessions/middleware.py b/django/contrib/sessions/middleware.py index 0f7a27148f..2af2312e76 100644 --- a/django/contrib/sessions/middleware.py +++ b/django/contrib/sessions/middleware.py @@ -1,9 +1,8 @@ import time -import datetime -from email.Utils import formatdate from django.conf import settings from django.utils.cache import patch_vary_headers +from django.utils.http import cookie_date TEST_COOKIE_NAME = 'testcookie' TEST_COOKIE_VALUE = 'worked' @@ -32,13 +31,8 @@ class SessionMiddleware(object): expires = None else: max_age = settings.SESSION_COOKIE_AGE - rfcdate = formatdate(time.time() + settings.SESSION_COOKIE_AGE) - - # 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") - + expires_time = time.time() + settings.SESSION_COOKIE_AGE + expires = cookie_date(expires_time) # Save the seesion data and refresh the client cookie. request.session.save() response.set_cookie(settings.SESSION_COOKIE_NAME, diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py index 411068b2f5..380e571b00 100644 --- a/django/core/servers/basehttp.py +++ b/django/core/servers/basehttp.py @@ -9,14 +9,14 @@ been reviewed for security issues. Don't use it for production use. from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer from types import ListType, StringType -from email.Utils import formatdate import mimetypes import os import re import sys -import time import urllib +from django.utils.http import http_date + __version__ = "0.1" __all__ = ['WSGIServer','WSGIRequestHandler','demo_app'] @@ -376,7 +376,7 @@ class ServerHandler(object): self._write('HTTP/%s %s\r\n' % (self.http_version,self.status)) if 'Date' not in self.headers: 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: self._write('Server: %s\r\n' % self.server_software) diff --git a/django/middleware/http.py b/django/middleware/http.py index 71cdf7aa5d..998fed4332 100644 --- a/django/middleware/http.py +++ b/django/middleware/http.py @@ -1,4 +1,4 @@ -from email.Utils import formatdate +from django.utils.http import http_date class ConditionalGetMiddleware(object): """ @@ -11,7 +11,7 @@ class ConditionalGetMiddleware(object): Also sets the Date and Content-Length response-headers. """ def process_response(self, request, response): - response['Date'] = formatdate()[:26] + "GMT" + response['Date'] = http_date() if not response.has_header('Content-Length'): response['Content-Length'] = str(len(response.content)) diff --git a/django/utils/cache.py b/django/utils/cache.py index 71544bd17e..ae4de6dd87 100644 --- a/django/utils/cache.py +++ b/django/utils/cache.py @@ -20,11 +20,11 @@ An example: i18n middleware would need to distinguish caches by the import md5 import re import time -from email.Utils import formatdate from django.conf import settings from django.core.cache import cache 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*') @@ -89,9 +89,9 @@ def patch_response_headers(response, cache_timeout=None): if not response.has_header('ETag'): response['ETag'] = md5.new(response.content).hexdigest() if not response.has_header('Last-Modified'): - response['Last-Modified'] = formatdate()[:26] + "GMT" + response['Last-Modified'] = http_date() 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) def add_never_cache_headers(response): diff --git a/django/utils/http.py b/django/utils/http.py index 4912c9c46a..5ec6e92d28 100644 --- a/django/utils/http.py +++ b/django/utils/http.py @@ -1,4 +1,6 @@ import urllib +from email.Utils import formatdate + from django.utils.encoding import smart_str, force_unicode from django.utils.functional import allow_lazy @@ -37,3 +39,29 @@ def urlencode(query, doseq=0): for k, v in query], 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] diff --git a/django/views/static.py b/django/views/static.py index dce45d914d..b556c60ca6 100644 --- a/django/views/static.py +++ b/django/views/static.py @@ -7,13 +7,14 @@ import mimetypes import os import posixpath import re -import rfc822 import stat import urllib +from email.Utils import parsedate_tz, mktime_tz from django.template import loader from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseNotModified from django.template import Template, Context, TemplateDoesNotExist +from django.utils.http import http_date 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] contents = open(fullpath, 'rb').read() 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 DEFAULT_DIRECTORY_INDEX_TEMPLATE = """ @@ -119,8 +120,7 @@ def was_modified_since(header=None, mtime=0, size=0): raise ValueError matches = re.match(r"^([^;]+)(; length=([0-9]+))?$", header, re.IGNORECASE) - header_mtime = rfc822.mktime_tz(rfc822.parsedate_tz( - matches.group(1))) + header_mtime = mktime_tz(parsedate_tz(matches.group(1))) header_len = matches.group(3) if header_len and int(header_len) != size: raise ValueError diff --git a/tests/regressiontests/text/tests.py b/tests/regressiontests/text/tests.py index 962a30ef19..7cfe44517a 100644 --- a/tests/regressiontests/text/tests.py +++ b/tests/regressiontests/text/tests.py @@ -27,6 +27,14 @@ u'Paris+%26+Orl%C3%A9ans' >>> urlquote_plus(u'Paris & Orl\xe9ans', safe="&") 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 ########################################################### >>> from django.utils.encoding import iri_to_uri >>> iri_to_uri(u'red%09ros\xe9#red')