Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/middleware/gzip.py: 23%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

35 statements  

1from django.utils.cache import patch_vary_headers 

2from django.utils.deprecation import MiddlewareMixin 

3from django.utils.regex_helper import _lazy_re_compile 

4from django.utils.text import compress_sequence, compress_string 

5 

6re_accepts_gzip = _lazy_re_compile(r"\bgzip\b") 

7 

8 

9class GZipMiddleware(MiddlewareMixin): 

10 """ 

11 Compress content if the browser allows gzip compression. 

12 Set the Vary header accordingly, so that caches will base their storage 

13 on the Accept-Encoding header. 

14 """ 

15 

16 max_random_bytes = 100 

17 

18 def process_response(self, request, response): 

19 # It's not worth attempting to compress really short responses. 

20 if not response.streaming and len(response.content) < 200: 

21 return response 

22 

23 # Avoid gzipping if we've already got a content-encoding. 

24 if response.has_header("Content-Encoding"): 

25 return response 

26 

27 patch_vary_headers(response, ("Accept-Encoding",)) 

28 

29 ae = request.META.get("HTTP_ACCEPT_ENCODING", "") 

30 if not re_accepts_gzip.search(ae): 

31 return response 

32 

33 if response.streaming: 

34 if response.is_async: 

35 # pull to lexical scope to capture fixed reference in case 

36 # streaming_content is set again later. 

37 orignal_iterator = response.streaming_content 

38 

39 async def gzip_wrapper(): 

40 async for chunk in orignal_iterator: 

41 yield compress_string( 

42 chunk, 

43 max_random_bytes=self.max_random_bytes, 

44 ) 

45 

46 response.streaming_content = gzip_wrapper() 

47 else: 

48 response.streaming_content = compress_sequence( 

49 response.streaming_content, 

50 max_random_bytes=self.max_random_bytes, 

51 ) 

52 # Delete the `Content-Length` header for streaming content, because 

53 # we won't know the compressed size until we stream it. 

54 del response.headers["Content-Length"] 

55 else: 

56 # Return the compressed content only if it's actually shorter. 

57 compressed_content = compress_string( 

58 response.content, 

59 max_random_bytes=self.max_random_bytes, 

60 ) 

61 if len(compressed_content) >= len(response.content): 

62 return response 

63 response.content = compressed_content 

64 response.headers["Content-Length"] = str(len(response.content)) 

65 

66 # If there is a strong ETag, make it weak to fulfill the requirements 

67 # of RFC 9110 Section 8.8.1 while also allowing conditional request 

68 # matches on ETags. 

69 etag = response.get("ETag") 

70 if etag and etag.startswith('"'): 

71 response.headers["ETag"] = "W/" + etag 

72 response.headers["Content-Encoding"] = "gzip" 

73 

74 return response