bug #26100 [Routing] Throw 405 instead of 404 when redirect is not possible (nicolas-grekas)
This PR was merged into the 2.7 branch.
Discussion
----------
[Routing] Throw 405 instead of 404 when redirect is not possible
| Q | A
| ------------- | ---
| Branch? | 2.7
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | -
| License | MIT
| Doc PR | -
Finishes #25962.
Commits
-------
92842814f6
[Routing] Throw 405 instead of 404 when redirect is not possible
This commit is contained in:
commit
aa3a04ad28
@ -217,7 +217,7 @@ EOF;
|
||||
$methods[] = 'HEAD';
|
||||
}
|
||||
|
||||
$supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods));
|
||||
$supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('GET', $methods));
|
||||
|
||||
if (!count($compiledRoute->getPathVariables()) && false !== preg_match('#^(.)\^(?P<url>.*?)\$\1#', $compiledRoute->getRegex(), $m)) {
|
||||
if ($supportsTrailingSlash && '/' === substr($m['url'], -1)) {
|
||||
@ -258,6 +258,42 @@ EOF;
|
||||
EOF;
|
||||
|
||||
$gotoname = 'not_'.preg_replace('/[^A-Za-z0-9_]/', '', $name);
|
||||
|
||||
if ($hasTrailingSlash) {
|
||||
$code .= <<<EOF
|
||||
if ('/' === substr(\$pathinfo, -1)) {
|
||||
// no-op
|
||||
} elseif (!in_array(\$this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
\$allow[] = 'GET';
|
||||
goto $gotoname;
|
||||
} else {
|
||||
return \$this->redirect(\$rawPathinfo.'/', '$name');
|
||||
}
|
||||
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
if ($schemes = $route->getSchemes()) {
|
||||
if (!$supportsRedirections) {
|
||||
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
|
||||
\$requiredSchemes = $schemes;
|
||||
if (!isset(\$requiredSchemes[\$this->context->getScheme()])) {
|
||||
if (!in_array(\$this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
\$allow[] = 'GET';
|
||||
goto $gotoname;
|
||||
}
|
||||
|
||||
return \$this->redirect(\$rawPathinfo, '$name', key(\$requiredSchemes));
|
||||
}
|
||||
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
if ($methods) {
|
||||
if (1 === count($methods)) {
|
||||
$code .= <<<EOF
|
||||
@ -281,35 +317,6 @@ EOF;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasTrailingSlash) {
|
||||
$code .= <<<EOF
|
||||
if ('/' === substr(\$pathinfo, -1)) {
|
||||
// no-op
|
||||
} elseif (!in_array(\$this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
goto $gotoname;
|
||||
} else {
|
||||
return \$this->redirect(\$rawPathinfo.'/', '$name');
|
||||
}
|
||||
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
if ($schemes = $route->getSchemes()) {
|
||||
if (!$supportsRedirections) {
|
||||
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
|
||||
\$requiredSchemes = $schemes;
|
||||
if (!isset(\$requiredSchemes[\$this->context->getScheme()])) {
|
||||
return \$this->redirect(\$rawPathinfo, '$name', key(\$requiredSchemes));
|
||||
}
|
||||
|
||||
|
||||
EOF;
|
||||
}
|
||||
|
||||
// optimize parameters array
|
||||
if ($matches || $hostMatches) {
|
||||
$vars = array();
|
||||
@ -333,7 +340,7 @@ EOF;
|
||||
}
|
||||
$code .= " }\n";
|
||||
|
||||
if ($methods || $hasTrailingSlash) {
|
||||
if ($hasTrailingSlash || $schemes || $methods) {
|
||||
$code .= " $gotoname:\n";
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
|
||||
if ('/' === substr($pathinfo, -1)) {
|
||||
// no-op
|
||||
} elseif (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
$allow[] = 'GET';
|
||||
goto not_baz3;
|
||||
} else {
|
||||
return $this->redirect($rawPathinfo.'/', 'baz3');
|
||||
@ -85,6 +86,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
|
||||
if ('/' === substr($pathinfo, -1)) {
|
||||
// no-op
|
||||
} elseif (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
$allow[] = 'GET';
|
||||
goto not_baz4;
|
||||
} else {
|
||||
return $this->redirect($rawPathinfo.'/', 'baz4');
|
||||
@ -183,6 +185,7 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
|
||||
if ('/' === substr($pathinfo, -1)) {
|
||||
// no-op
|
||||
} elseif (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
$allow[] = 'GET';
|
||||
goto not_hey;
|
||||
} else {
|
||||
return $this->redirect($rawPathinfo.'/', 'hey');
|
||||
@ -333,21 +336,33 @@ class ProjectUrlMatcher extends Symfony\Component\Routing\Tests\Fixtures\Redirec
|
||||
if ('/secure' === $pathinfo) {
|
||||
$requiredSchemes = array ( 'https' => 0,);
|
||||
if (!isset($requiredSchemes[$this->context->getScheme()])) {
|
||||
if (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
$allow[] = 'GET';
|
||||
goto not_secure;
|
||||
}
|
||||
|
||||
return $this->redirect($rawPathinfo, 'secure', key($requiredSchemes));
|
||||
}
|
||||
|
||||
return array('_route' => 'secure');
|
||||
}
|
||||
not_secure:
|
||||
|
||||
// nonsecure
|
||||
if ('/nonsecure' === $pathinfo) {
|
||||
$requiredSchemes = array ( 'http' => 0,);
|
||||
if (!isset($requiredSchemes[$this->context->getScheme()])) {
|
||||
if (!in_array($this->context->getMethod(), array('HEAD', 'GET'))) {
|
||||
$allow[] = 'GET';
|
||||
goto not_nonsecure;
|
||||
}
|
||||
|
||||
return $this->redirect($rawPathinfo, 'nonsecure', key($requiredSchemes));
|
||||
}
|
||||
|
||||
return array('_route' => 'nonsecure');
|
||||
}
|
||||
not_nonsecure:
|
||||
|
||||
throw 0 < count($allow) ? new MethodNotAllowedException(array_unique($allow)) : new ResourceNotFoundException();
|
||||
}
|
||||
|
@ -19,6 +19,14 @@ use Symfony\Component\Routing\RequestContext;
|
||||
|
||||
class DumpedRedirectableUrlMatcherTest extends RedirectableUrlMatcherTest
|
||||
{
|
||||
/**
|
||||
* @expectedException \Symfony\Component\Routing\Exception\MethodNotAllowedException
|
||||
*/
|
||||
public function testRedirectWhenNoSlashForNonSafeMethod()
|
||||
{
|
||||
parent::testRedirectWhenNoSlashForNonSafeMethod();
|
||||
}
|
||||
|
||||
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
|
||||
{
|
||||
static $i = 0;
|
||||
|
Reference in New Issue
Block a user