Refs #19705 -- Made GZipMiddleware make ETags weak.
Django's conditional request processing can now produce 304 Not Modified responses for content that is subject to compression.
This commit is contained in:
parent
816eae3508
commit
ad332e5ca9
|
@ -41,8 +41,12 @@ class GZipMiddleware(MiddlewareMixin):
|
||||||
response.content = compressed_content
|
response.content = compressed_content
|
||||||
response['Content-Length'] = str(len(response.content))
|
response['Content-Length'] = str(len(response.content))
|
||||||
|
|
||||||
if response.has_header('ETag'):
|
# If there is a strong ETag, make it weak to fulfill the requirements
|
||||||
response['ETag'] = re.sub('"$', ';gzip"', response['ETag'])
|
# of RFC 7232 section-2.1 while also allowing conditional request
|
||||||
|
# matches on ETags.
|
||||||
|
etag = response.get('ETag')
|
||||||
|
if etag and etag.startswith('"'):
|
||||||
|
response['ETag'] = 'W/' + etag
|
||||||
response['Content-Encoding'] = 'gzip'
|
response['Content-Encoding'] = 'gzip'
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
|
@ -155,6 +155,9 @@ It will NOT compress content if any of the following are true:
|
||||||
* The request (the browser) hasn't sent an ``Accept-Encoding`` header
|
* The request (the browser) hasn't sent an ``Accept-Encoding`` header
|
||||||
containing ``gzip``.
|
containing ``gzip``.
|
||||||
|
|
||||||
|
If the response has an ``ETag`` header, the ETag is made weak to comply with
|
||||||
|
:rfc:`7232#section-2.1`.
|
||||||
|
|
||||||
You can apply GZip compression to individual views using the
|
You can apply GZip compression to individual views using the
|
||||||
:func:`~django.views.decorators.gzip.gzip_page()` decorator.
|
:func:`~django.views.decorators.gzip.gzip_page()` decorator.
|
||||||
|
|
||||||
|
|
|
@ -855,27 +855,44 @@ class GZipMiddlewareTest(SimpleTestCase):
|
||||||
@override_settings(USE_ETAGS=True)
|
@override_settings(USE_ETAGS=True)
|
||||||
class ETagGZipMiddlewareTest(SimpleTestCase):
|
class ETagGZipMiddlewareTest(SimpleTestCase):
|
||||||
"""
|
"""
|
||||||
Tests if the ETagMiddleware behaves correctly with GZipMiddleware.
|
ETags are handled properly by GZipMiddleware.
|
||||||
"""
|
"""
|
||||||
rf = RequestFactory()
|
rf = RequestFactory()
|
||||||
compressible_string = b'a' * 500
|
compressible_string = b'a' * 500
|
||||||
|
|
||||||
def test_compress_response(self):
|
def test_strong_etag_modified(self):
|
||||||
"""
|
"""
|
||||||
ETag is changed after gzip compression is performed.
|
GZipMiddleware makes a strong ETag weak.
|
||||||
|
"""
|
||||||
|
request = self.rf.get('/', HTTP_ACCEPT_ENCODING='gzip, deflate')
|
||||||
|
response = HttpResponse(self.compressible_string)
|
||||||
|
response['ETag'] = '"eggs"'
|
||||||
|
gzip_response = GZipMiddleware().process_response(request, response)
|
||||||
|
self.assertEqual(gzip_response['ETag'], 'W/"eggs"')
|
||||||
|
|
||||||
|
def test_weak_etag_not_modified(self):
|
||||||
|
"""
|
||||||
|
GZipMiddleware doesn't modify a weak ETag.
|
||||||
|
"""
|
||||||
|
request = self.rf.get('/', HTTP_ACCEPT_ENCODING='gzip, deflate')
|
||||||
|
response = HttpResponse(self.compressible_string)
|
||||||
|
response['ETag'] = 'W/"eggs"'
|
||||||
|
gzip_response = GZipMiddleware().process_response(request, response)
|
||||||
|
self.assertEqual(gzip_response['ETag'], 'W/"eggs"')
|
||||||
|
|
||||||
|
def test_etag_match(self):
|
||||||
|
"""
|
||||||
|
GZipMiddleware allows 304 Not Modified responses.
|
||||||
"""
|
"""
|
||||||
request = self.rf.get('/', HTTP_ACCEPT_ENCODING='gzip, deflate')
|
request = self.rf.get('/', HTTP_ACCEPT_ENCODING='gzip, deflate')
|
||||||
response = GZipMiddleware().process_response(
|
response = GZipMiddleware().process_response(
|
||||||
request,
|
request,
|
||||||
CommonMiddleware().process_response(request, HttpResponse(self.compressible_string))
|
ConditionalGetMiddleware().process_response(request, HttpResponse(self.compressible_string))
|
||||||
)
|
)
|
||||||
gzip_etag = response.get('ETag')
|
gzip_etag = response['ETag']
|
||||||
|
next_request = self.rf.get('/', HTTP_ACCEPT_ENCODING='gzip, deflate', HTTP_IF_NONE_MATCH=gzip_etag)
|
||||||
request = self.rf.get('/', HTTP_ACCEPT_ENCODING='')
|
next_response = ConditionalGetMiddleware().process_response(
|
||||||
response = GZipMiddleware().process_response(
|
next_request,
|
||||||
request,
|
HttpResponse(self.compressible_string)
|
||||||
CommonMiddleware().process_response(request, HttpResponse(self.compressible_string))
|
|
||||||
)
|
)
|
||||||
nogzip_etag = response.get('ETag')
|
self.assertEqual(next_response.status_code, 304)
|
||||||
|
|
||||||
self.assertNotEqual(gzip_etag, nogzip_etag)
|
|
||||||
|
|
Loading…
Reference in New Issue