Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed #24137 -- Use default reason phrases from HTTP standard. #3902

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 0 additions & 3 deletions django/core/handlers/wsgi.py
Expand Up @@ -16,9 +16,6 @@
from django.utils.functional import cached_property
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')

# encode() and decode() expect the charset to be a native string.
Expand Down
68 changes: 2 additions & 66 deletions django/http/response.py
Expand Up @@ -17,73 +17,10 @@
from django.utils.encoding import force_bytes, force_text, force_str, iri_to_uri
from django.utils.http import cookie_date
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


# 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)


Expand Down Expand Up @@ -118,8 +55,7 @@ def __init__(self, content_type=None, status=None, reason=None, charset=None):
if reason is not None:
self.reason_phrase = reason
elif self.reason_phrase is None:
self.reason_phrase = REASON_PHRASES.get(self.status_code,
'UNKNOWN STATUS CODE')
self.reason_phrase = responses.get(self.status_code, 'Unknown Status Code')
self._charset = charset
if content_type is None:
content_type = '%s; charset=%s' % (settings.DEFAULT_CONTENT_TYPE,
Expand Down
14 changes: 14 additions & 0 deletions docs/ref/request-response.txt
Expand Up @@ -629,6 +629,13 @@ Attributes

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

This is always ``False``.
Expand Down Expand Up @@ -980,6 +987,13 @@ Attributes

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

This is always ``True``.
Expand Down
7 changes: 7 additions & 0 deletions docs/releases/1.9.txt
Expand Up @@ -171,6 +171,13 @@ Miscellaneous
* CSS and images in ``contrib.admin`` to support Internet Explorer 6 & 7 have
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:

Features deprecated in 1.9
Expand Down
6 changes: 3 additions & 3 deletions tests/responses/tests.py
Expand Up @@ -50,9 +50,9 @@ def test_setdefault(self):

class HttpResponseTests(SimpleTestCase):
def test_status_code(self):
resp = HttpResponse(status=418)
self.assertEqual(resp.status_code, 418)
self.assertEqual(resp.reason_phrase, "I'M A TEAPOT")
resp = HttpResponse(status=503)
self.assertEqual(resp.status_code, 503)
self.assertEqual(resp.reason_phrase, "Service Unavailable")

def test_reason_phrase(self):
reason = "I'm an anarchist coffee pot on crack."
Expand Down