From 2c80da2f79b681a6e6b6bec650c1dc1b36d2d28e Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Thu, 27 Aug 2020 12:29:25 -0400 Subject: [PATCH] Fix issue in Router with paths beginning with multiple slashes --- src/Routing/Router.php | 18 +++++++++++++----- tests/Routing/RouterTest.php | 24 +++++++++++++++++++++--- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/Routing/Router.php b/src/Routing/Router.php index 7248f0b..ba9ea8f 100644 --- a/src/Routing/Router.php +++ b/src/Routing/Router.php @@ -78,22 +78,21 @@ class Router implements MiddlewareInterface ResponseInterface $response, $next ): ResponseInterface { - // Use only the path for routing. - $requestTarget = parse_url($request->getRequestTarget(), PHP_URL_PATH); + $path = $this->getPath($request->getRequestTarget()); - $route = $this->getStaticRoute($requestTarget); + $route = $this->getStaticRoute($path); if ($route) { return $this->dispatch($route, $request, $response, $next); } - $route = $this->getPrefixRoute($requestTarget); + $route = $this->getPrefixRoute($path); if ($route) { return $this->dispatch($route, $request, $response, $next); } // Try each of the routes. foreach ($this->patternRoutes as $route) { - if ($route->matchesRequestTarget($requestTarget)) { + if ($route->matchesRequestTarget($path)) { $pathVariables = $route->getPathVariables(); if ($this->pathVariablesAttributeName) { $request = $request->withAttribute($this->pathVariablesAttributeName, $pathVariables); @@ -113,6 +112,15 @@ class Router implements MiddlewareInterface return $next($request, $response); } + private function getPath(string $requestTarget): string + { + $queryStart = strpos($requestTarget, '?'); + if ($queryStart === false) { + return $requestTarget; + } + return substr($requestTarget, 0, $queryStart); + } + private function dispatch( callable $route, ServerRequestInterface $request, diff --git a/tests/Routing/RouterTest.php b/tests/Routing/RouterTest.php index d5541aa..904cb0a 100644 --- a/tests/Routing/RouterTest.php +++ b/tests/Routing/RouterTest.php @@ -291,7 +291,8 @@ class RouterTest extends TestCase public function testMatchesPathAgainstRouteWithoutQuery(): void { - $target = '/my/path?cat=molly&dog=bear'; + $path = '/my/path'; + $target = $path . '?cat=molly&dog=bear'; $this->request = $this->request->withRequestTarget($target); @@ -299,11 +300,28 @@ class RouterTest extends TestCase $this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); - $this->router->register('GET', $target, 'middleware'); + $this->router->register('GET', $path, 'middleware'); $this->dispatch(); - $this->route->matchesRequestTarget('/my/path')->shouldHaveBeenCalled(); + $this->route->matchesRequestTarget($path)->shouldHaveBeenCalled(); + } + + public function testMatchesPathWithDuplicateLeadingSlashes(): void + { + $path = '//my/path'; + + $this->request = $this->request->withRequestTarget($path); + + $this->route->getTarget()->willReturn($path); + $this->route->getType()->willReturn(Route::TYPE_PATTERN); + $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); + + $this->router->register('GET', $path, 'middleware'); + + $this->dispatch(); + + $this->route->matchesRequestTarget($path)->shouldHaveBeenCalled(); } // -------------------------------------------------------------------------