Skip to content

Commit

Permalink
bug #26312 [Routing] Don't throw 405 when scheme requirement doesn't …
Browse files Browse the repository at this point in the history
…match (nicolas-grekas)

This PR was merged into the 2.7 branch.

Discussion
----------

[Routing] Don't throw 405 when scheme requirement doesn't match

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #22739
| License       | MIT
| Doc PR        | -

Commits
-------

9d70ef0 [Routing] Don't throw 405 when scheme requirement doesn't match
  • Loading branch information
nicolas-grekas committed Feb 26, 2018
2 parents 0acbf2b + 9d70ef0 commit 4f14fff
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 11 deletions.
29 changes: 25 additions & 4 deletions src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
Expand Up @@ -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 .= <<<EOF
if ($methods) {
$methods = implode("', '", $methods);
$code .= <<<EOF
\$requiredSchemes = $schemes;
if (!isset(\$requiredSchemes[\$this->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;
}
Expand All @@ -290,9 +299,21 @@ private function compileRoute(Route $route, $name, $supportsRedirections, $paren
EOF;
}
} else {
$code .= <<<EOF
\$requiredSchemes = $schemes;
if (!isset(\$requiredSchemes[\$this->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 .= <<<EOF
if (\$this->context->getMethod() != '$methods[0]') {
Expand Down
16 changes: 9 additions & 7 deletions src/Symfony/Component/Routing/Matcher/UrlMatcher.php
Expand Up @@ -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
Expand All @@ -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));
}
}
Expand Down
Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
Expand Up @@ -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());
Expand Down

0 comments on commit 4f14fff

Please sign in to comment.