1
0
mirror of https://github.com/django/django.git synced 2025-10-26 07:06:08 +00:00

Fixed #31789 -- Added a new headers interface to HttpResponse.

This commit is contained in:
Tom Carrick
2020-07-14 13:32:24 +02:00
committed by Mariusz Felisiak
parent 71ae1ab012
commit bcc2befd0e
47 changed files with 385 additions and 256 deletions

View File

@@ -292,44 +292,44 @@ class HttpResponseTests(unittest.TestCase):
r = HttpResponse()
# ASCII strings or bytes values are converted to strings.
r['key'] = 'test'
self.assertEqual(r['key'], 'test')
r['key'] = b'test'
self.assertEqual(r['key'], 'test')
r.headers['key'] = 'test'
self.assertEqual(r.headers['key'], 'test')
r.headers['key'] = b'test'
self.assertEqual(r.headers['key'], 'test')
self.assertIn(b'test', r.serialize_headers())
# Non-ASCII values are serialized to Latin-1.
r['key'] = 'café'
r.headers['key'] = 'café'
self.assertIn('café'.encode('latin-1'), r.serialize_headers())
# Other Unicode values are MIME-encoded (there's no way to pass them as
# bytes).
r['key'] = ''
self.assertEqual(r['key'], '=?utf-8?b?4oCg?=')
r.headers['key'] = ''
self.assertEqual(r.headers['key'], '=?utf-8?b?4oCg?=')
self.assertIn(b'=?utf-8?b?4oCg?=', r.serialize_headers())
# The response also converts string or bytes keys to strings, but requires
# them to contain ASCII
r = HttpResponse()
del r['Content-Type']
r['foo'] = 'bar'
headers = list(r.items())
del r.headers['Content-Type']
r.headers['foo'] = 'bar'
headers = list(r.headers.items())
self.assertEqual(len(headers), 1)
self.assertEqual(headers[0], ('foo', 'bar'))
r = HttpResponse()
del r['Content-Type']
r[b'foo'] = 'bar'
headers = list(r.items())
del r.headers['Content-Type']
r.headers[b'foo'] = 'bar'
headers = list(r.headers.items())
self.assertEqual(len(headers), 1)
self.assertEqual(headers[0], ('foo', 'bar'))
self.assertIsInstance(headers[0][0], str)
r = HttpResponse()
with self.assertRaises(UnicodeError):
r.__setitem__('føø', 'bar')
r.headers.__setitem__('føø', 'bar')
with self.assertRaises(UnicodeError):
r.__setitem__('føø'.encode(), 'bar')
r.headers.__setitem__('føø'.encode(), 'bar')
def test_long_line(self):
# Bug #20889: long lines trigger newlines to be added to headers
@@ -337,18 +337,18 @@ class HttpResponseTests(unittest.TestCase):
h = HttpResponse()
f = b'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz a\xcc\x88'
f = f.decode('utf-8')
h['Content-Disposition'] = 'attachment; filename="%s"' % f
h.headers['Content-Disposition'] = 'attachment; filename="%s"' % f
# This one is triggering https://bugs.python.org/issue20747, that is Python
# will itself insert a newline in the header
h['Content-Disposition'] = 'attachment; filename="EdelRot_Blu\u0308te (3)-0.JPG"'
h.headers['Content-Disposition'] = 'attachment; filename="EdelRot_Blu\u0308te (3)-0.JPG"'
def test_newlines_in_headers(self):
# Bug #10188: Do not allow newlines in headers (CR or LF)
r = HttpResponse()
with self.assertRaises(BadHeaderError):
r.__setitem__('test\rstr', 'test')
r.headers.__setitem__('test\rstr', 'test')
with self.assertRaises(BadHeaderError):
r.__setitem__('test\nstr', 'test')
r.headers.__setitem__('test\nstr', 'test')
def test_dict_behavior(self):
"""
@@ -436,7 +436,7 @@ class HttpResponseTests(unittest.TestCase):
# with Content-Encoding header
r = HttpResponse()
r['Content-Encoding'] = 'winning'
r.headers['Content-Encoding'] = 'winning'
r.write(b'abc')
r.write(b'def')
self.assertEqual(r.content, b'abcdef')
@@ -462,6 +462,14 @@ class HttpResponseTests(unittest.TestCase):
with self.assertRaises(DisallowedRedirect):
HttpResponsePermanentRedirect(url)
def test_header_deletion(self):
r = HttpResponse('hello')
r.headers['X-Foo'] = 'foo'
del r.headers['X-Foo']
self.assertNotIn('X-Foo', r.headers)
# del doesn't raise a KeyError on nonexistent headers.
del r.headers['X-Foo']
class HttpResponseSubclassesTests(SimpleTestCase):
def test_redirect(self):
@@ -474,7 +482,7 @@ class HttpResponseSubclassesTests(SimpleTestCase):
content_type='text/html',
)
self.assertContains(response, 'The resource has temporarily moved', status_code=302)
self.assertEqual(response.url, response['Location'])
self.assertEqual(response.url, response.headers['Location'])
def test_redirect_lazy(self):
"""Make sure HttpResponseRedirect works with lazy strings."""
@@ -523,7 +531,7 @@ class HttpResponseSubclassesTests(SimpleTestCase):
def test_not_allowed_repr_no_content_type(self):
response = HttpResponseNotAllowed(('GET', 'POST'))
del response['Content-Type']
del response.headers['Content-Type']
self.assertEqual(repr(response), '<HttpResponseNotAllowed [GET, POST] status_code=405>')
@@ -785,3 +793,32 @@ class CookieTests(unittest.TestCase):
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
C1 = pickle.loads(pickle.dumps(C, protocol=proto))
self.assertEqual(C1.output(), expected_output)
class HttpResponseHeadersTestCase(SimpleTestCase):
"""Headers by treating HttpResponse like a dictionary."""
def test_headers(self):
response = HttpResponse()
response['X-Foo'] = 'bar'
self.assertEqual(response['X-Foo'], 'bar')
self.assertEqual(response.headers['X-Foo'], 'bar')
self.assertIn('X-Foo', response)
self.assertIs(response.has_header('X-Foo'), True)
del response['X-Foo']
self.assertNotIn('X-Foo', response)
self.assertNotIn('X-Foo', response.headers)
# del doesn't raise a KeyError on nonexistent headers.
del response['X-Foo']
def test_headers_bytestring(self):
response = HttpResponse()
response['X-Foo'] = b'bar'
self.assertEqual(response['X-Foo'], 'bar')
self.assertEqual(response.headers['X-Foo'], 'bar')
def test_newlines_in_headers(self):
response = HttpResponse()
with self.assertRaises(BadHeaderError):
response['test\rstr'] = 'test'
with self.assertRaises(BadHeaderError):
response['test\nstr'] = 'test'