From 02fe881d27c1bca59efcf808f72801871bd1b7bd Mon Sep 17 00:00:00 2001 From: KnifeLemon Date: Fri, 24 Apr 2026 02:33:12 +0900 Subject: [PATCH] fix wildcard routes being skipped by fast path method lookup closes #693 Co-authored-by: Copilot --- flight/net/Router.php | 20 ++++++++------------ tests/RouterTest.php | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/flight/net/Router.php b/flight/net/Router.php index 8c2c6e1..0ec9724 100644 --- a/flight/net/Router.php +++ b/flight/net/Router.php @@ -152,7 +152,7 @@ class Router if (!isset($this->routesByMethod[$method])) { $this->routesByMethod[$method] = []; } - $this->routesByMethod[$method][] = $route; + $this->routesByMethod[$method][count($this->routes) - 1] = $route; } return $route; @@ -270,17 +270,13 @@ class Router } // Fast path: check method-specific routes first, then wildcard routes (only on first routing attempt) - $methodsToCheck = [$requestMethod, '*']; - foreach ($methodsToCheck as $method) { - if (isset($this->routesByMethod[$method])) { - foreach ($this->routesByMethod[$method] as $route) { - if ($route->matchUrl($requestUrl, $this->caseSensitive)) { - $this->executedRoute = $route; - // Set iterator position to this route for potential next() calls - $this->index = array_search($route, $this->routes, true); - return $route; - } - } + $candidates = ($this->routesByMethod[$requestMethod] ?? []) + ($this->routesByMethod['*'] ?? []); + ksort($candidates); + foreach ($candidates as $routeIndex => $route) { + if ($route->matchUrl($requestUrl, $this->caseSensitive)) { + $this->executedRoute = $route; + $this->index = $routeIndex; + return $route; } } diff --git a/tests/RouterTest.php b/tests/RouterTest.php index fb62958..cc07a10 100644 --- a/tests/RouterTest.php +++ b/tests/RouterTest.php @@ -780,4 +780,21 @@ class RouterTest extends TestCase $this->request->method = 'GET'; $this->check('OK'); } + + public function testWildcardPassthroughRouteBeforeSpecificGetRoute(): void + { + $this->router->map('/@par/[^\/]+/*', function (string $par): bool { + echo "Passthrough (Par = $par)"; + return true; + }); + + $this->router->map('GET /[^\/]+/target', function (): void { + echo ' Target'; + }); + + $this->request->url = '/foobar/target/'; + $this->request->method = 'GET'; + + $this->check('Passthrough (Par = foobar) Target'); + } }