From d5a8237b1cc73a7a75505fd3c8d2be6789c24a44 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 25 May 2018 18:30:16 +0200 Subject: [PATCH] [Routing] Account for greediness when merging route patterns --- .../Matcher/Dumper/StaticPrefixCollection.php | 12 +++++ .../Tests/Fixtures/dumper/url_matcher11.php | 54 +++++++++---------- .../Routing/Tests/Matcher/UrlMatcherTest.php | 10 ++++ 3 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/StaticPrefixCollection.php b/src/Symfony/Component/Routing/Matcher/Dumper/StaticPrefixCollection.php index 05315defcc..cd9e6b4c3e 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/StaticPrefixCollection.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/StaticPrefixCollection.php @@ -151,6 +151,7 @@ class StaticPrefixCollection $baseLength = \strlen($this->prefix); $end = min(\strlen($prefix), \strlen($anotherPrefix)); $staticLength = null; + set_error_handler(array(__CLASS__, 'handleError')); for ($i = $baseLength; $i < $end && $prefix[$i] === $anotherPrefix[$i]; ++$i) { if ('(' === $prefix[$i]) { @@ -174,13 +175,24 @@ class StaticPrefixCollection if (('?' === ($prefix[$j] ?? '') || '?' === ($anotherPrefix[$j] ?? '')) && ($prefix[$j] ?? '') !== ($anotherPrefix[$j] ?? '')) { break; } + $subPattern = substr($prefix, $i, $j - $i); + if ($prefix !== $anotherPrefix && !preg_match('/^\(\[[^\]]++\]\+\+\)$/', $subPattern) && !preg_match('{(? array(array('_route' => 'a', '_locale' => 'en'), array('_locale'), null, null), 43 => array(array('_route' => 'b', '_locale' => 'en'), array('_locale'), null, null), - 58 => array(array('_route' => 'c', '_locale' => 'en'), array('_locale', 'id'), null, null), - 73 => array(array('_route' => 'd', '_locale' => 'en'), array('_locale', 'id'), null, null), - 86 => array(array('_route' => 'e', '_locale' => 'en'), array('_locale', 'id'), null, null), - 104 => array(array('_route' => 'f', '_locale' => 'en'), array('_locale'), null, null), - 120 => array(array('_route' => 'g', '_locale' => 'en'), array('_locale'), null, null), - 144 => array(array('_route' => 'h', '_locale' => 'en'), array('_locale', 'page'), null, null), - 165 => array(array('_route' => 'i', '_locale' => 'en'), array('_locale', 'page'), null, null), - 192 => array(array('_route' => 'j', '_locale' => 'en'), array('_locale', 'id'), null, null), - 206 => array(array('_route' => 'k', '_locale' => 'en'), array('_locale'), null, null), - 223 => array(array('_route' => 'l', '_locale' => 'en'), array('_locale'), null, null), - 234 => array(array('_route' => 'm', '_locale' => 'en'), array('_locale'), null, null), - 253 => array(array('_route' => 'n', '_locale' => 'en'), array('_locale'), null, null), + 55 => array(array('_route' => 'c', '_locale' => 'en'), array('_locale', 'id'), null, null), + 72 => array(array('_route' => 'd', '_locale' => 'en'), array('_locale', 'id'), null, null), + 91 => array(array('_route' => 'e', '_locale' => 'en'), array('_locale', 'id'), null, null), + 107 => array(array('_route' => 'f', '_locale' => 'en'), array('_locale'), null, null), + 123 => array(array('_route' => 'g', '_locale' => 'en'), array('_locale'), null, null), + 147 => array(array('_route' => 'h', '_locale' => 'en'), array('_locale', 'page'), null, null), + 168 => array(array('_route' => 'i', '_locale' => 'en'), array('_locale', 'page'), null, null), + 195 => array(array('_route' => 'j', '_locale' => 'en'), array('_locale', 'id'), null, null), + 209 => array(array('_route' => 'k', '_locale' => 'en'), array('_locale'), null, null), + 226 => array(array('_route' => 'l', '_locale' => 'en'), array('_locale'), null, null), + 237 => array(array('_route' => 'm', '_locale' => 'en'), array('_locale'), null, null), + 256 => array(array('_route' => 'n', '_locale' => 'en'), array('_locale'), null, null), ); list($ret, $vars, $requiredMethods, $requiredSchemes) = $routes[$m]; @@ -139,7 +135,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec return $ret; } - if (253 === $m) { + if (256 === $m) { break; } $regex = substr_replace($regex, 'F', $m - $offset, 1 + strlen($m)); diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 0ba61c9486..b3bfd78271 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -611,6 +611,16 @@ class UrlMatcherTest extends TestCase $this->assertEquals(array('_route' => 'a', 'a' => 'a', 'b' => 'b'), $matcher->match('/a/b')); } + public function testDotAllWithCatchAll() + { + $coll = new RouteCollection(); + $coll->add('a', new Route('/{id}.html', array(), array('id' => '.+'))); + $coll->add('b', new Route('/{all}', array(), array('all' => '.+'))); + + $matcher = $this->getUrlMatcher($coll); + $this->assertEquals(array('_route' => 'a', 'id' => 'foo/bar'), $matcher->match('/foo/bar.html')); + } + protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return new UrlMatcher($routes, $context ?: new RequestContext());