You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Code breaks for dynamic routes. The __call__method of depends/RateLimiter checks for matches via if route.path == request.scope["path"] and request.method in route.methods: in the block below
route_index = 0
dep_index = 0
for i, route in enumerate(request.app.routes):
if route.path == request.scope["path"] and request.method in route.methods:
route_index = i
for j, dependency in enumerate(route.dependencies):
if self is dependency.dependency:
dep_index = j
break
route.path is generic and for dynamic routes is like /path/to/{id} but request.scope["path"] is the actual realized path like /path/to/51 or /path/to/186 so they never match and because route_index and dep_index are both initalized to 0, they are 0 when the loop exits leading to key collisions for all dynamic routes (and also anything that coincidentally does match the 0th route and 0th dependency). The key for all dynamic routes will be f"{prefix}:{identifier}:0:0".
Proposed Fix
route.path should be checked against request.scope["route"].path (instead of against request.scope["path"])
def _get_indices(self, request):
request_path = request.scope["route"].path
for route_index, route in enumerate(request.app.routes):
if route.path == request_path:
if request.method in route.methods:
for dep_index, dependency in enumerate(route.dependencies):
if self is dependency.dependency:
return route_index, dep_index
// Debatable how to handle this case, I just raise a ValueError
raise ValueError(f"No matching dependency found for dependency of route {request_path}")
raise ValueError(f"No matching route found for route {request_path}")
async def __call__(self, request: Request, response: Response):
if not FastAPILimiter.redis:
raise Exception("You must call FastAPILimiter.init in startup event of fastapi!")
route_index, dep_index = self._get_indices(request)
Also in the current version there are key collisions for different Methods on the same route, this can be fixed by including the request.method in the key. Here is how I chose to use my key as it makes it clear what's what in case I ever have to revisit in the future and debug inside redis.
Bug
Code breaks for dynamic routes. The __call__method of depends/RateLimiter checks for matches via
if route.path == request.scope["path"] and request.method in route.methods:
in the block belowroute.path
is generic and for dynamic routes is like/path/to/{id}
butrequest.scope["path"]
is the actual realized path like/path/to/51
or/path/to/186
so they never match and becauseroute_index
anddep_index
are both initalized to 0, they are 0 when the loop exits leading to key collisions for all dynamic routes (and also anything that coincidentally does match the 0th route and 0th dependency). The key for all dynamic routes will be f"{prefix}:{identifier}:0:0".Proposed Fix
route.path should be checked against
request.scope["route"].path(instead of against request.scope["path"])
Also in the current version there are key collisions for different Methods on the same route, this can be fixed by including the request.method in the key. Here is how I chose to use my key as it makes it clear what's what in case I ever have to revisit in the future and debug inside redis.
key = f"{FastAPILimiter.prefix}:{user_identifier}:route{route_index}-dep{dep_index}-{request.method}"
The text was updated successfully, but these errors were encountered: