Coverage for ivatar/middleware.py: 95%
22 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 11:51 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 11:51 +0000
1"""
2Middleware classes
3"""
5import hashlib
6from django.utils.deprecation import MiddlewareMixin
7from django.middleware.locale import LocaleMiddleware
10class CustomLocaleMiddleware(LocaleMiddleware):
11 """
12 Middleware that extends LocaleMiddleware to skip Vary header processing for image URLs
13 """
15 def process_response(self, request, response):
16 # Check if this is an image-related URL
17 path = request.path
18 if any(
19 path.startswith(prefix)
20 for prefix in ["/avatar/", "/gravatarproxy/", "/blueskyproxy/"]
21 ):
22 # Delete Vary from header if exists
23 if "Vary" in response:
24 del response["Vary"]
26 # Extract hash from URL path for ETag
27 # URLs are like /avatar/{hash}, /gravatarproxy/{hash}, /blueskyproxy/{hash}
28 path_parts = path.strip("/").split("/")
29 if len(path_parts) >= 2:
30 hash_value = path_parts[1] # Get the hash part
31 # Sanitize hash_value to remove newlines and other control characters
32 # that would cause BadHeaderError
33 hash_value = "".join(
34 c for c in hash_value if c.isprintable() and c not in "\r\n"
35 )
36 response["Etag"] = f'"{hash_value}"'
37 else:
38 # Fallback to content hash if we can't extract from URL
39 # Use hashlib.md5 for stable hash across processes
40 content_hash = hashlib.md5(response.content).hexdigest()
41 response["Etag"] = f'"{content_hash}"'
43 # Skip the parent's process_response to avoid adding Accept-Language to Vary
44 return response
46 # For all other URLs, use the parent's behavior
47 return super().process_response(request, response)
50class MultipleProxyMiddleware(
51 MiddlewareMixin
52): # pylint: disable=too-few-public-methods
53 """
54 Middleware to rewrite proxy headers for deployments
55 with multiple proxies
56 """
58 def process_request(self, request): # pylint: disable=no-self-use
59 """
60 Rewrites the proxy headers so that forwarded server is
61 used if available.
62 """
63 if "HTTP_X_FORWARDED_SERVER" in request.META:
64 request.META["HTTP_X_FORWARDED_HOST"] = request.META[
65 "HTTP_X_FORWARDED_SERVER"
66 ]