From d2e57a336d43efb313b8430ae045f588c47e4e46 Mon Sep 17 00:00:00 2001 From: Ben Darnell Date: Fri, 24 May 2013 00:41:23 -0400 Subject: [PATCH] Revert change to use time.strftime (from 3.0). time.strftime is influenced by the user's locale (if one is set with locale.setlocale), so it's not what we want. Go back to the (slower) email.utils functions. Fixes #800. --- tornado/httputil.py | 12 +++++++----- tornado/test/runtests.py | 3 +++ tornado/test/web_test.py | 5 +++-- tornado/web.py | 2 +- tox.ini | 6 +++++- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/tornado/httputil.py b/tornado/httputil.py index 36d7dc8f..3d17b610 100644 --- a/tornado/httputil.py +++ b/tornado/httputil.py @@ -18,8 +18,10 @@ from __future__ import absolute_import, division, print_function, with_statement +import calendar import collections import datetime +import email.utils import numbers import re import time @@ -382,15 +384,15 @@ def format_timestamp(ts): >>> format_timestamp(1359312200) 'Sun, 27 Jan 2013 18:43:20 GMT' """ - if isinstance(ts, (tuple, time.struct_time)): + if isinstance(ts, numbers.Real): pass + elif isinstance(ts, (tuple, time.struct_time)): + ts = calendar.timegm(ts) elif isinstance(ts, datetime.datetime): - ts = ts.utctimetuple() - elif isinstance(ts, numbers.Real): - ts = time.gmtime(ts) + ts = calendar.timegm(ts.utctimetuple()) else: raise TypeError("unknown timestamp type: %r" % ts) - return time.strftime("%a, %d %b %Y %H:%M:%S GMT", ts) + return email.utils.formatdate(ts, usegmt=True) # _parseparam and _parse_header are copied and modified from python2.7's cgi.py # The original 2.7 version of this code did not correctly support some diff --git a/tornado/test/runtests.py b/tornado/test/runtests.py index 22cda522..1f4c08c9 100644 --- a/tornado/test/runtests.py +++ b/tornado/test/runtests.py @@ -2,6 +2,7 @@ from __future__ import absolute_import, division, print_function, with_statement import gc +import locale # system locale module, not tornado.locale import logging import operator import textwrap @@ -95,6 +96,8 @@ if __name__ == '__main__': "e.g. DEBUG_STATS or DEBUG_COLLECTABLE,DEBUG_OBJECTS", callback=lambda values: gc.set_debug( reduce(operator.or_, (getattr(gc, v) for v in values)))) + define('locale', type=str, default=None, + callback=lambda x: locale.setlocale(locale.LC_ALL, x)) def configure_ioloop(): kwargs = {} diff --git a/tornado/test/web_test.py b/tornado/test/web_test.py index 74eec11e..d3884393 100644 --- a/tornado/test/web_test.py +++ b/tornado/test/web_test.py @@ -13,6 +13,7 @@ from tornado.web import RequestHandler, authenticated, Application, asynchronous import binascii import datetime +import email.utils import logging import os import re @@ -1160,8 +1161,8 @@ class DateHeaderTest(SimpleHandlerTestCase): def test_date_header(self): response = self.fetch('/') - header_date = datetime.datetime.strptime(response.headers['Date'], - "%a, %d %b %Y %H:%M:%S GMT") + header_date = datetime.datetime( + *email.utils.parsedate(response.headers['Date'])[:6]) self.assertTrue(header_date - datetime.datetime.utcnow() < datetime.timedelta(seconds=2)) diff --git a/tornado/web.py b/tornado/web.py index 2ede8d32..f670d8aa 100644 --- a/tornado/web.py +++ b/tornado/web.py @@ -239,7 +239,7 @@ class RequestHandler(object): self._headers = httputil.HTTPHeaders({ "Server": "TornadoServer/%s" % tornado.version, "Content-Type": "text/html; charset=UTF-8", - "Date": httputil.format_timestamp(time.gmtime()), + "Date": httputil.format_timestamp(time.time()), }) self.set_default_headers() if (not self.request.supports_http_1_1() and diff --git a/tox.ini b/tox.ini index 95ab47af..3d143c3a 100644 --- a/tox.ini +++ b/tox.ini @@ -11,7 +11,7 @@ [tox] # "-full" variants include optional dependencies, to ensure # that things work both in a bare install and with all the extras. -envlist = py27-full, py27-curl, py32-full, pypy, py26, py26-full, py27, py32, py32-utf8, py33, py27-opt, py32-opt, pypy-full, py27-select, py27-monotonic, py33-monotonic, py27-twisted, py27-threadedresolver, py27-twistedresolver, py27-twistedlayered, py27-caresresolver, py32-caresresolver, py27-docs +envlist = py27-full, py27-curl, py32-full, pypy, py26, py26-full, py27, py32, py32-utf8, py33, py27-opt, py32-opt, pypy-full, py27-select, py27-monotonic, py33-monotonic, py27-twisted, py27-threadedresolver, py27-twistedresolver, py27-twistedlayered, py27-caresresolver, py32-caresresolver, py27-locale, py27-docs [testenv] commands = python -m tornado.test.runtests {posargs:} @@ -138,6 +138,10 @@ deps = twisted commands = python -m tornado.test.runtests --resolver=tornado.platform.caresresolver.CaresResolver {posargs:} +[testenv:py27-locale] +basepython = python2.7 +commands = python -m tornado.test.runtests --locale=zh_TW {posargs:} + [testenv:pypy-full] # This configuration works with pypy 1.9. pycurl installs ok but # curl_httpclient doesn't work. Twisted works most of the time, but