mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Refs #19705 -- Changed gzip modification times to 0.
This makes gzip output deterministic, which allows ConditionalGetMiddleware to reliably compare ETags on gzipped content (views using the gzip_page() decorator in particular).
This commit is contained in:
		
				
					committed by
					
						 Tim Graham
						Tim Graham
					
				
			
			
				
	
			
			
			
						parent
						
							9eb49af821
						
					
				
				
					commit
					9108696a75
				
			| @@ -293,7 +293,7 @@ def phone2numeric(phone): | |||||||
| # Used with permission. | # Used with permission. | ||||||
| def compress_string(s): | def compress_string(s): | ||||||
|     zbuf = BytesIO() |     zbuf = BytesIO() | ||||||
|     with GzipFile(mode='wb', compresslevel=6, fileobj=zbuf) as zfile: |     with GzipFile(mode='wb', compresslevel=6, fileobj=zbuf, mtime=0) as zfile: | ||||||
|         zfile.write(s) |         zfile.write(s) | ||||||
|     return zbuf.getvalue() |     return zbuf.getvalue() | ||||||
|  |  | ||||||
| @@ -322,7 +322,7 @@ class StreamingBuffer(object): | |||||||
| # Like compress_string, but for iterators of strings. | # Like compress_string, but for iterators of strings. | ||||||
| def compress_sequence(sequence): | def compress_sequence(sequence): | ||||||
|     buf = StreamingBuffer() |     buf = StreamingBuffer() | ||||||
|     with GzipFile(mode='wb', compresslevel=6, fileobj=buf) as zfile: |     with GzipFile(mode='wb', compresslevel=6, fileobj=buf, mtime=0) as zfile: | ||||||
|         # Output headers... |         # Output headers... | ||||||
|         yield buf.read() |         yield buf.read() | ||||||
|         for item in sequence: |         for item in sequence: | ||||||
|   | |||||||
| @@ -770,6 +770,12 @@ class GZipMiddlewareTest(SimpleTestCase): | |||||||
|         with gzip.GzipFile(mode='rb', fileobj=BytesIO(gzipped_string)) as f: |         with gzip.GzipFile(mode='rb', fileobj=BytesIO(gzipped_string)) as f: | ||||||
|             return f.read() |             return f.read() | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|  |     def get_mtime(gzipped_string): | ||||||
|  |         with gzip.GzipFile(mode='rb', fileobj=BytesIO(gzipped_string)) as f: | ||||||
|  |             f.read()  # must read the data before accessing the header | ||||||
|  |             return f.mtime | ||||||
|  |  | ||||||
|     def test_compress_response(self): |     def test_compress_response(self): | ||||||
|         """ |         """ | ||||||
|         Compression is performed on responses with compressible content. |         Compression is performed on responses with compressible content. | ||||||
| @@ -850,6 +856,20 @@ class GZipMiddlewareTest(SimpleTestCase): | |||||||
|         self.assertEqual(r.content, self.incompressible_string) |         self.assertEqual(r.content, self.incompressible_string) | ||||||
|         self.assertIsNone(r.get('Content-Encoding')) |         self.assertIsNone(r.get('Content-Encoding')) | ||||||
|  |  | ||||||
|  |     def test_compress_deterministic(self): | ||||||
|  |         """ | ||||||
|  |         Compression results are the same for the same content and don't | ||||||
|  |         include a modification time (since that would make the results | ||||||
|  |         of compression non-deterministic and prevent | ||||||
|  |         ConditionalGetMiddleware from recognizing conditional matches | ||||||
|  |         on gzipped content). | ||||||
|  |         """ | ||||||
|  |         r1 = GZipMiddleware().process_response(self.req, self.resp) | ||||||
|  |         r2 = GZipMiddleware().process_response(self.req, self.resp) | ||||||
|  |         self.assertEqual(r1.content, r2.content) | ||||||
|  |         self.assertEqual(self.get_mtime(r1.content), 0) | ||||||
|  |         self.assertEqual(self.get_mtime(r2.content), 0) | ||||||
|  |  | ||||||
|  |  | ||||||
| @ignore_warnings(category=RemovedInDjango21Warning) | @ignore_warnings(category=RemovedInDjango21Warning) | ||||||
| @override_settings(USE_ETAGS=True) | @override_settings(USE_ETAGS=True) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user