perf: stop recomputing static work in per-response ASGI middlewares (#27229)
SecurityHeadersMiddleware called set_security_headers() on every response — 14 os.environ.get lookups plus a regex validation per configured header, for values that are static for the process lifetime. Compute the header list once at construction; when no security env vars are set, skip wrapping send entirely. RedirectMiddleware decoded and parse_qs'd the query string of every GET, though it only acts on /watch?v= and ?shared= URLs. Add a cheap path/substring precheck first; a false positive just falls through to the previous full parse, so no redirect behavior changes. Verified byte-identical responses (status, Location, header values) against the previous implementations across redirect, passthrough, and no-env cases. Claude-Session: https://claude.ai/code/session_01MHg5zs1VBjvRWQ54qHpfYD Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -227,7 +227,15 @@ class RedirectMiddleware:
|
||||
return
|
||||
|
||||
path = scope.get('path', '')
|
||||
query_string = scope.get('query_string', b'').decode('latin-1', errors='replace')
|
||||
raw_query = scope.get('query_string', b'')
|
||||
# This middleware only acts on /watch?v= and ?shared= URLs; skip the
|
||||
# decode + parse_qs work for every other GET. (A false positive on the
|
||||
# substring check just falls through to the full parse below.)
|
||||
if not (path.endswith('/watch') or b'shared' in raw_query):
|
||||
await self.app(scope, receive, send)
|
||||
return
|
||||
|
||||
query_string = raw_query.decode('latin-1', errors='replace')
|
||||
query_params = parse_qs(query_string)
|
||||
|
||||
redirect_params: dict[str, str] = {}
|
||||
|
||||
@@ -15,16 +15,19 @@ class SecurityHeadersMiddleware:
|
||||
|
||||
def __init__(self, app: ASGIApp) -> None:
|
||||
self.app = app
|
||||
# Headers derive only from env vars, which are static for the process
|
||||
# lifetime — compute them once instead of per response.
|
||||
self._headers = list(set_security_headers().items())
|
||||
|
||||
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
||||
if scope['type'] != 'http':
|
||||
if scope['type'] != 'http' or not self._headers:
|
||||
await self.app(scope, receive, send)
|
||||
return
|
||||
|
||||
async def send_with_security_headers(message: Message) -> None:
|
||||
if message['type'] == 'http.response.start':
|
||||
headers = MutableHeaders(scope=message)
|
||||
for key, value in set_security_headers().items():
|
||||
for key, value in self._headers:
|
||||
headers[key] = value
|
||||
await send(message)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user