Fixed #24137 -- Switched to HTTP reason phrases from Python stdlib.

This commit is contained in:
Jon Dufresne 2015-01-13 11:29:07 -08:00 committed by Tim Graham
parent 0f3ea8c0bc
commit 24b2bc635e
5 changed files with 26 additions and 72 deletions

View File

@ -16,9 +16,6 @@ from django.utils.encoding import force_str, force_text
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils import six from django.utils import six
# For backwards compatibility -- lots of code uses this in the wild!
from django.http.response import REASON_PHRASES as STATUS_CODE_TEXT # NOQA
logger = logging.getLogger('django.request') logger = logging.getLogger('django.request')
# encode() and decode() expect the charset to be a native string. # encode() and decode() expect the charset to be a native string.

View File

@ -17,73 +17,10 @@ from django.utils import six, timezone
from django.utils.encoding import force_bytes, force_text, force_str, iri_to_uri from django.utils.encoding import force_bytes, force_text, force_str, iri_to_uri
from django.utils.http import cookie_date from django.utils.http import cookie_date
from django.utils.six.moves import map from django.utils.six.moves import map
from django.utils.six.moves.http_client import responses
from django.utils.six.moves.urllib.parse import urlparse from django.utils.six.moves.urllib.parse import urlparse
# See http://www.iana.org/assignments/http-status-codes
REASON_PHRASES = {
100: 'CONTINUE',
101: 'SWITCHING PROTOCOLS',
102: 'PROCESSING',
200: 'OK',
201: 'CREATED',
202: 'ACCEPTED',
203: 'NON-AUTHORITATIVE INFORMATION',
204: 'NO CONTENT',
205: 'RESET CONTENT',
206: 'PARTIAL CONTENT',
207: 'MULTI-STATUS',
208: 'ALREADY REPORTED',
226: 'IM USED',
300: 'MULTIPLE CHOICES',
301: 'MOVED PERMANENTLY',
302: 'FOUND',
303: 'SEE OTHER',
304: 'NOT MODIFIED',
305: 'USE PROXY',
306: 'RESERVED',
307: 'TEMPORARY REDIRECT',
308: 'PERMANENT REDIRECT',
400: 'BAD REQUEST',
401: 'UNAUTHORIZED',
402: 'PAYMENT REQUIRED',
403: 'FORBIDDEN',
404: 'NOT FOUND',
405: 'METHOD NOT ALLOWED',
406: 'NOT ACCEPTABLE',
407: 'PROXY AUTHENTICATION REQUIRED',
408: 'REQUEST TIMEOUT',
409: 'CONFLICT',
410: 'GONE',
411: 'LENGTH REQUIRED',
412: 'PRECONDITION FAILED',
413: 'REQUEST ENTITY TOO LARGE',
414: 'REQUEST-URI TOO LONG',
415: 'UNSUPPORTED MEDIA TYPE',
416: 'REQUESTED RANGE NOT SATISFIABLE',
417: 'EXPECTATION FAILED',
418: "I'M A TEAPOT",
422: 'UNPROCESSABLE ENTITY',
423: 'LOCKED',
424: 'FAILED DEPENDENCY',
426: 'UPGRADE REQUIRED',
428: 'PRECONDITION REQUIRED',
429: 'TOO MANY REQUESTS',
431: 'REQUEST HEADER FIELDS TOO LARGE',
500: 'INTERNAL SERVER ERROR',
501: 'NOT IMPLEMENTED',
502: 'BAD GATEWAY',
503: 'SERVICE UNAVAILABLE',
504: 'GATEWAY TIMEOUT',
505: 'HTTP VERSION NOT SUPPORTED',
506: 'VARIANT ALSO NEGOTIATES',
507: 'INSUFFICIENT STORAGE',
508: 'LOOP DETECTED',
510: 'NOT EXTENDED',
511: 'NETWORK AUTHENTICATION REQUIRED',
}
_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)
@ -118,8 +55,7 @@ class HttpResponseBase(six.Iterator):
if reason is not None: if reason is not None:
self.reason_phrase = reason self.reason_phrase = reason
elif self.reason_phrase is None: elif self.reason_phrase is None:
self.reason_phrase = REASON_PHRASES.get(self.status_code, self.reason_phrase = responses.get(self.status_code, 'Unknown Status Code')
'UNKNOWN STATUS CODE')
self._charset = charset self._charset = charset
if content_type is None: if content_type is None:
content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE, content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE,

View File

@ -629,6 +629,13 @@ Attributes
The HTTP reason phrase for the response. The HTTP reason phrase for the response.
.. versionchanged:: 1.9
``reason_phrase`` no longer defaults to all capital letters. It now
uses the `HTTP standard's`_ default reason phrases.
.. _`HTTP standard's`: https://www.ietf.org/rfc/rfc2616.txt
.. attribute:: HttpResponse.streaming .. attribute:: HttpResponse.streaming
This is always ``False``. This is always ``False``.
@ -980,6 +987,13 @@ Attributes
The HTTP reason phrase for the response. The HTTP reason phrase for the response.
.. versionchanged:: 1.9
``reason_phrase`` no longer defaults to all capital letters. It now
uses the `HTTP standard's`_ default reason phrases.
.. _`HTTP standard's`: https://www.ietf.org/rfc/rfc2616.txt
.. attribute:: StreamingHttpResponse.streaming .. attribute:: StreamingHttpResponse.streaming
This is always ``True``. This is always ``True``.

View File

@ -171,6 +171,13 @@ Miscellaneous
* CSS and images in ``contrib.admin`` to support Internet Explorer 6 & 7 have * CSS and images in ``contrib.admin`` to support Internet Explorer 6 & 7 have
been removed as these browsers have reached end-of-life. been removed as these browsers have reached end-of-life.
* ``django.http.responses.REASON_PHRASES`` and
``django.core.handlers.wsgi.STATUS_CODE_TEXT`` have been removed. Use
Python's stdlib instead: :data:`http.client.responses` for Python 3 and
`httplib.responses`_ for Python 2.
.. _`httplib.responses`: https://docs.python.org/2/library/httplib.html#httplib.responses
.. _deprecated-features-1.9: .. _deprecated-features-1.9:
Features deprecated in 1.9 Features deprecated in 1.9

View File

@ -50,9 +50,9 @@ class HttpResponseBaseTests(SimpleTestCase):
class HttpResponseTests(SimpleTestCase): class HttpResponseTests(SimpleTestCase):
def test_status_code(self): def test_status_code(self):
resp = HttpResponse(status=418) resp = HttpResponse(status=503)
self.assertEqual(resp.status_code, 418) self.assertEqual(resp.status_code, 503)
self.assertEqual(resp.reason_phrase, "I'M A TEAPOT") self.assertEqual(resp.reason_phrase, "Service Unavailable")
def test_reason_phrase(self): def test_reason_phrase(self):
reason = "I'm an anarchist coffee pot on crack." reason = "I'm an anarchist coffee pot on crack."