@@ -60,19 +60,28 @@ async def dispatch(self, request: Request, call_next: RequestResponseEndpoint):
6060_HEALTH_PATHS = {"/health" , "/healthz" , "/ready" , "/readiness" , "/liveness" }
6161
6262
63- class TrailingSlashMiddleware ( BaseHTTPMiddleware ) :
63+ class TrailingSlashMiddleware :
6464 """Strip trailing slashes before routing.
6565
66- Avoids 307 redirects for clients (e.g. Quarkus REST Client) that do not
67- re-send the Authorization header when following a redirect.
66+ Pure ASGI middleware (not BaseHTTPMiddleware) so the modified scope is
67+ guaranteed to reach the router. Avoids 307 redirects for clients such as
68+ Quarkus REST Client that do not re-send the Authorization header when
69+ following a redirect.
6870 """
6971
70- async def dispatch (self , request : Request , call_next : RequestResponseEndpoint ):
71- if request .url .path != "/" and request .url .path .endswith ("/" ):
72- scope = dict (request .scope )
73- scope ["path" ] = request .url .path .rstrip ("/" )
74- request = Request (scope , request .receive , request ._send )
75- return await call_next (request )
72+ def __init__ (self , app : Any ) -> None :
73+ self .app = app
74+
75+ async def __call__ (self , scope : Any , receive : Any , send : Any ) -> None :
76+ if scope .get ("type" ) == "http" :
77+ path : str = scope .get ("path" , "" )
78+ if path != "/" and path .endswith ("/" ):
79+ scope = dict (scope )
80+ scope ["path" ] = path .rstrip ("/" )
81+ raw_path : bytes = scope .get ("raw_path" , b"" )
82+ if raw_path .endswith (b"/" ):
83+ scope ["raw_path" ] = raw_path .rstrip (b"/" )
84+ await self .app (scope , receive , send )
7685
7786
7887class ExceptionHandlerMiddleware (BaseHTTPMiddleware ):
0 commit comments