Skip to content

Commit

Permalink
[Routing] fix trailing slash redirection when using RedirectableUrlMa…
Browse files Browse the repository at this point in the history
…tcher
  • Loading branch information
nicolas-grekas committed Nov 26, 2018
1 parent f747ea9 commit dc4c3f6
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 2 deletions.
25 changes: 23 additions & 2 deletions src/Symfony/Component/Routing/Matcher/UrlMatcher.php
Expand Up @@ -118,18 +118,39 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac
*/
protected function matchCollection($pathinfo, RouteCollection $routes)
{
$supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface;

foreach ($routes as $name => $route) {
$compiledRoute = $route->compile();
$staticPrefix = $compiledRoute->getStaticPrefix();

// check the static prefix of the URL first. Only use the more expensive preg_match when it matches
if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) {
if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) {
// no-op
} elseif (!$supportsTrailingSlash) {
continue;
} elseif ('/' === substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) {
return;
} else {
continue;
}
$regex = $compiledRoute->getRegex();

if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) {
$regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2);
$hasTrailingSlash = true;
} else {
$hasTrailingSlash = false;
}

if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) {
if (!preg_match($regex, $pathinfo, $matches)) {
continue;
}

if ($hasTrailingSlash && '/' !== substr($pathinfo, -1)) {
return;
}

$hostMatches = array();
if ($compiledRoute->getHostRegex() && !preg_match($compiledRoute->getHostRegex(), $this->context->getHost(), $hostMatches)) {
continue;
Expand Down
Expand Up @@ -117,6 +117,17 @@ public function testSchemeRequirement()
$this->assertSame(array('_route' => 'foo'), $matcher->match('/foo'));
}

public function testFallbackPage()
{
$coll = new RouteCollection();
$coll->add('foo', new Route('/foo/'));
$coll->add('bar', new Route('/{name}'));

$matcher = $this->getUrlMatcher($coll);
$matcher->expects($this->once())->method('redirect')->with('/foo/')->will($this->returnValue(array('_route' => 'foo')));
$this->assertSame(array('_route' => 'foo'), $matcher->match('/foo'));
}

protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return $this->getMockForAbstractClass('Symfony\Component\Routing\Matcher\RedirectableUrlMatcher', array($routes, $context ?: new RequestContext()));
Expand Down

0 comments on commit dc4c3f6

Please sign in to comment.