From 7521af7ea0d0cd77604c7c11bfd58714cec776e3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 3 Dec 2018 14:19:27 +0100 Subject: [PATCH] [Routing] ignore trailing slash for non-GET requests --- .../Component/Routing/Matcher/UrlMatcher.php | 13 ++++++------- .../Routing/Tests/Matcher/UrlMatcherTest.php | 11 +++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index fc4554fff52d..4b6494288ec6 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -118,6 +118,10 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac */ protected function matchCollection($pathinfo, RouteCollection $routes) { + // HEAD and GET are equivalent as per RFC + if ('HEAD' === $method = $this->context->getMethod()) { + $method = 'GET'; + } $supportsTrailingSlash = '/' !== $pathinfo && '' !== $pathinfo && $this instanceof RedirectableUrlMatcherInterface; foreach ($routes as $name => $route) { @@ -128,7 +132,7 @@ protected function matchCollection($pathinfo, RouteCollection $routes) // check the static prefix of the URL first. Only use the more expensive preg_match when it matches if ('' === $staticPrefix || 0 === strpos($pathinfo, $staticPrefix)) { // no-op - } elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods))) { + } elseif (!$supportsTrailingSlash || ($requiredMethods && !\in_array('GET', $requiredMethods)) || 'GET' !== $method) { continue; } elseif ('/' === substr($staticPrefix, -1) && substr($staticPrefix, 0, -1) === $pathinfo) { return $this->allow = array(); @@ -149,7 +153,7 @@ protected function matchCollection($pathinfo, RouteCollection $routes) } if ($hasTrailingSlash && '/' !== substr($pathinfo, -1)) { - if (!$requiredMethods || \in_array('GET', $requiredMethods)) { + if ((!$requiredMethods || \in_array('GET', $requiredMethods)) && 'GET' === $method) { return $this->allow = array(); } continue; @@ -168,11 +172,6 @@ protected function matchCollection($pathinfo, RouteCollection $routes) // check HTTP method requirement if ($requiredMethods) { - // HEAD and GET are equivalent as per RFC - if ('HEAD' === $method = $this->context->getMethod()) { - $method = 'GET'; - } - if (!\in_array($method, $requiredMethods)) { if (self::REQUIREMENT_MATCH === $status[0]) { $this->allow = array_merge($this->allow, $requiredMethods); diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index ab682732ca31..85647f0bead2 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -514,6 +514,17 @@ public function testSlashAndVerbPrecedence() 'customerId' => '123', ); $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); + + $coll = new RouteCollection(); + $coll->add('a', new Route('/api/customers/{customerId}/contactpersons/', array(), array(), array(), '', array(), array('get'))); + $coll->add('b', new Route('/api/customers/{customerId}/contactpersons', array(), array(), array(), '', array(), array('post'))); + + $matcher = $this->getUrlMatcher($coll, new RequestContext('', 'POST')); + $expected = array( + '_route' => 'b', + 'customerId' => '123', + ); + $this->assertEquals($expected, $matcher->match('/api/customers/123/contactpersons')); } protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)