Fix issue in Router with paths beginning with multiple slashes

This commit is contained in:
PJ Dietz 2020-08-27 12:29:25 -04:00
parent a15b5396e9
commit 2c80da2f79
2 changed files with 34 additions and 8 deletions

View File

@ -78,22 +78,21 @@ class Router implements MiddlewareInterface
ResponseInterface $response, ResponseInterface $response,
$next $next
): ResponseInterface { ): ResponseInterface {
// Use only the path for routing. $path = $this->getPath($request->getRequestTarget());
$requestTarget = parse_url($request->getRequestTarget(), PHP_URL_PATH);
$route = $this->getStaticRoute($requestTarget); $route = $this->getStaticRoute($path);
if ($route) { if ($route) {
return $this->dispatch($route, $request, $response, $next); return $this->dispatch($route, $request, $response, $next);
} }
$route = $this->getPrefixRoute($requestTarget); $route = $this->getPrefixRoute($path);
if ($route) { if ($route) {
return $this->dispatch($route, $request, $response, $next); return $this->dispatch($route, $request, $response, $next);
} }
// Try each of the routes. // Try each of the routes.
foreach ($this->patternRoutes as $route) { foreach ($this->patternRoutes as $route) {
if ($route->matchesRequestTarget($requestTarget)) { if ($route->matchesRequestTarget($path)) {
$pathVariables = $route->getPathVariables(); $pathVariables = $route->getPathVariables();
if ($this->pathVariablesAttributeName) { if ($this->pathVariablesAttributeName) {
$request = $request->withAttribute($this->pathVariablesAttributeName, $pathVariables); $request = $request->withAttribute($this->pathVariablesAttributeName, $pathVariables);
@ -113,6 +112,15 @@ class Router implements MiddlewareInterface
return $next($request, $response); 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( private function dispatch(
callable $route, callable $route,
ServerRequestInterface $request, ServerRequestInterface $request,

View File

@ -291,7 +291,8 @@ class RouterTest extends TestCase
public function testMatchesPathAgainstRouteWithoutQuery(): void 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); $this->request = $this->request->withRequestTarget($target);
@ -299,11 +300,28 @@ class RouterTest extends TestCase
$this->route->getType()->willReturn(Route::TYPE_PATTERN); $this->route->getType()->willReturn(Route::TYPE_PATTERN);
$this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true);
$this->router->register('GET', $target, 'middleware'); $this->router->register('GET', $path, 'middleware');
$this->dispatch(); $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();
} }
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------