From 9d70ef0915cb2cbc8afe1bdc5edcbfc1b1b7b99e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 25 Feb 2018 22:38:00 +0100 Subject: [PATCH] [Routing] Don't throw 405 when scheme requirement doesn't match --- .../Matcher/Dumper/PhpMatcherDumper.php | 29 ++++++++++++++++--- .../Component/Routing/Matcher/UrlMatcher.php | 16 +++++----- .../Tests/Matcher/DumpedUrlMatcherTest.php | 9 ++++++ .../Routing/Tests/Matcher/UrlMatcherTest.php | 12 ++++++++ 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php index 0ff82a2c938e..8701dfd304a4 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php @@ -278,9 +278,18 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren throw new \LogicException('The "schemes" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.'); } $schemes = str_replace("\n", '', var_export(array_flip($schemes), true)); - $code .= <<context->getScheme()])) { + \$hasRequiredScheme = isset(\$requiredSchemes[\$this->context->getScheme()]); + if (!in_array(\$this->context->getMethod(), array('$methods'))) { + if (\$hasRequiredScheme) { + \$allow = array_merge(\$allow, array('$methods')); + } + goto $gotoname; + } + if (!\$hasRequiredScheme) { if (!in_array(\$this->context->getMethod(), array('HEAD', 'GET'))) { goto $gotoname; } @@ -290,9 +299,21 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren EOF; - } + } else { + $code .= <<context->getScheme()])) { + if (!in_array(\$this->context->getMethod(), array('HEAD', 'GET'))) { + goto $gotoname; + } - if ($methods) { + return \$this->redirect(\$rawPathinfo, '$name', key(\$requiredSchemes)); + } + + +EOF; + } + } elseif ($methods) { if (1 === count($methods)) { $code .= <<context->getMethod() != '$methods[0]') { diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index 1ef92827dccb..e2b9f1471077 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -129,6 +129,12 @@ protected function matchCollection($pathinfo, RouteCollection $routes) continue; } + $status = $this->handleRouteRequirements($pathinfo, $name, $route); + + if (self::REQUIREMENT_MISMATCH === $status[0]) { + continue; + } + // check HTTP method requirement if ($requiredMethods = $route->getMethods()) { // HEAD and GET are equivalent as per RFC @@ -137,22 +143,18 @@ protected function matchCollection($pathinfo, RouteCollection $routes) } if (!in_array($method, $requiredMethods)) { - $this->allow = array_merge($this->allow, $requiredMethods); + if (self::REQUIREMENT_MATCH === $status[0]) { + $this->allow = array_merge($this->allow, $requiredMethods); + } continue; } } - $status = $this->handleRouteRequirements($pathinfo, $name, $route); - if (self::ROUTE_MATCH === $status[0]) { return $status[1]; } - if (self::REQUIREMENT_MISMATCH === $status[0]) { - continue; - } - return $this->getAttributes($route, $name, array_replace($matches, $hostMatches)); } } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/DumpedUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/DumpedUrlMatcherTest.php index cc7eb8e2d730..e36a0220d9c2 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/DumpedUrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/DumpedUrlMatcherTest.php @@ -26,6 +26,15 @@ public function testSchemeRequirement() parent::testSchemeRequirement(); } + /** + * @expectedException \LogicException + * @expectedExceptionMessage The "schemes" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface. + */ + public function testSchemeAndMethodMismatch() + { + parent::testSchemeRequirement(); + } + protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { static $i = 0; diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 1fc78294c7ab..8328962ae4bd 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -464,6 +464,18 @@ public function testNestedCollections() $this->assertEquals(array('_route' => 'buz'), $matcher->match('/prefix/buz')); } + /** + * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException + */ + public function testSchemeAndMethodMismatch() + { + $coll = new RouteCollection(); + $coll->add('foo', new Route('/', array(), array(), array(), null, array('https'), array('POST'))); + + $matcher = $this->getUrlMatcher($coll); + $matcher->match('/'); + } + protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return new UrlMatcher($routes, $context ?: new RequestContext());