mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
FIX Don't redirect admin URLs regardless of trailing slash (#10781)
This commit is contained in:
parent
4a2dc2dd97
commit
2afb01463b
@ -412,7 +412,10 @@ class CanonicalURLMiddleware implements HTTPMiddleware
|
|||||||
$paths = (array) $this->getEnforceTrailingSlashConfigIgnorePaths();
|
$paths = (array) $this->getEnforceTrailingSlashConfigIgnorePaths();
|
||||||
if (!empty($paths)) {
|
if (!empty($paths)) {
|
||||||
foreach ($paths as $path) {
|
foreach ($paths as $path) {
|
||||||
if (str_starts_with(trim($path, '/'), trim($requestPath, '/'))) {
|
if (str_starts_with(
|
||||||
|
$this->trailingSlashForComparison($requestPath),
|
||||||
|
$this->trailingSlashForComparison($path)
|
||||||
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,6 +442,15 @@ class CanonicalURLMiddleware implements HTTPMiddleware
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure a string has a trailing slash to that we can use str_starts_with and compare
|
||||||
|
* paths like admin/ with administration/ and get a correct result.
|
||||||
|
*/
|
||||||
|
private function trailingSlashForComparison(string $path): string
|
||||||
|
{
|
||||||
|
return trim($path, '/') . '/';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
|
@ -85,63 +85,42 @@ class CanonicalURLMiddlewareTest extends SapphireTest
|
|||||||
$this->assertFalse($middleware->getForceBasicAuthToSSL(), 'Explicitly set is returned');
|
$this->assertFalse($middleware->getForceBasicAuthToSSL(), 'Explicitly set is returned');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRedirectTrailingSlash()
|
public function provideRedirectTrailingSlash()
|
||||||
{
|
{
|
||||||
$testScenarios = [
|
$testScenarios = [];
|
||||||
[
|
foreach ([true, false] as $forceRedirect) {
|
||||||
'forceRedirect' => true,
|
foreach ([true, false] as $addTrailingSlash) {
|
||||||
'addTrailingSlash' => true,
|
foreach ([true, false] as $requestHasSlash) {
|
||||||
'requestHasSlash' => true,
|
$testScenarios[] = [
|
||||||
],
|
$forceRedirect,
|
||||||
[
|
$addTrailingSlash,
|
||||||
'forceRedirect' => true,
|
$requestHasSlash,
|
||||||
'addTrailingSlash' => true,
|
|
||||||
'requestHasSlash' => false,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'forceRedirect' => true,
|
|
||||||
'addTrailingSlash' => false,
|
|
||||||
'requestHasSlash' => true,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'forceRedirect' => true,
|
|
||||||
'addTrailingSlash' => false,
|
|
||||||
'requestHasSlash' => false,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'forceRedirect' => false,
|
|
||||||
'addTrailingSlash' => true,
|
|
||||||
'requestHasSlash' => true,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'forceRedirect' => false,
|
|
||||||
'addTrailingSlash' => true,
|
|
||||||
'requestHasSlash' => false,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'forceRedirect' => false,
|
|
||||||
'addTrailingSlash' => false,
|
|
||||||
'requestHasSlash' => true,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'forceRedirect' => false,
|
|
||||||
'addTrailingSlash' => false,
|
|
||||||
'requestHasSlash' => false,
|
|
||||||
],
|
|
||||||
];
|
];
|
||||||
foreach ($testScenarios as $scenario) {
|
}
|
||||||
$forceRedirect = $scenario['forceRedirect'];
|
}
|
||||||
$addTrailingSlash = $scenario['addTrailingSlash'];
|
}
|
||||||
$requestHasSlash = $scenario['requestHasSlash'];
|
return $testScenarios;
|
||||||
|
}
|
||||||
|
|
||||||
$middleware = $this->getMockedMiddleware(false);
|
/**
|
||||||
|
* @dataProvider provideRedirectTrailingSlash
|
||||||
$middleware->setEnforceTrailingSlashConfig($forceRedirect);
|
*/
|
||||||
|
public function testRedirectTrailingSlash(bool $forceRedirect, bool $addTrailingSlash, bool $requestHasSlash)
|
||||||
|
{
|
||||||
Controller::config()->set('add_trailing_slash', $addTrailingSlash);
|
Controller::config()->set('add_trailing_slash', $addTrailingSlash);
|
||||||
|
|
||||||
|
$noRedirect = !$forceRedirect || ($addTrailingSlash && $requestHasSlash) || (!$addTrailingSlash && !$requestHasSlash);
|
||||||
|
$middleware = $this->getMockedMiddleware(false);
|
||||||
|
$middleware->setEnforceTrailingSlashConfig($forceRedirect);
|
||||||
|
|
||||||
$requestSlash = $requestHasSlash ? '/' : '';
|
$requestSlash = $requestHasSlash ? '/' : '';
|
||||||
$requestURL = "/about-us{$requestSlash}";
|
$requestURL = "/about-us{$requestSlash}";
|
||||||
|
|
||||||
|
$this->performRedirectTest($requestURL, $middleware, !$noRedirect, $addTrailingSlash);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function performRedirectTest(string $requestURL, CanonicalURLMiddleware $middleware, bool $shouldRedirect, bool $addTrailingSlash)
|
||||||
|
{
|
||||||
Environment::setEnv('REQUEST_URI', $requestURL);
|
Environment::setEnv('REQUEST_URI', $requestURL);
|
||||||
$request = new HTTPRequest('GET', $requestURL);
|
$request = new HTTPRequest('GET', $requestURL);
|
||||||
$request->setScheme('https');
|
$request->setScheme('https');
|
||||||
@ -153,8 +132,7 @@ class CanonicalURLMiddlewareTest extends SapphireTest
|
|||||||
return $mockResponse;
|
return $mockResponse;
|
||||||
});
|
});
|
||||||
|
|
||||||
$noRedirect = !$forceRedirect || ($addTrailingSlash && $requestHasSlash) || (!$addTrailingSlash && !$requestHasSlash);
|
if (!$shouldRedirect) {
|
||||||
if ($noRedirect) {
|
|
||||||
$this->assertNull($result->getHeader('Location'), 'No location header should be added');
|
$this->assertNull($result->getHeader('Location'), 'No location header should be added');
|
||||||
$this->assertEquals(200, $result->getStatusCode(), 'No redirection should be made');
|
$this->assertEquals(200, $result->getStatusCode(), 'No redirection should be made');
|
||||||
} else {
|
} else {
|
||||||
@ -166,6 +144,56 @@ class CanonicalURLMiddlewareTest extends SapphireTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideRedirectTrailingSlashIgnorePaths()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
'addTrailingSlash' => false,
|
||||||
|
'requestHasSlash' => false,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'addTrailingSlash' => false,
|
||||||
|
'requestHasSlash' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'addTrailingSlash' => true,
|
||||||
|
'requestHasSlash' => true,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'addTrailingSlash' => true,
|
||||||
|
'requestHasSlash' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider provideRedirectTrailingSlashIgnorePaths
|
||||||
|
*/
|
||||||
|
public function testRedirectTrailingSlashIgnorePaths(bool $addTrailingSlash, bool $requestHasSlash)
|
||||||
|
{
|
||||||
|
Controller::config()->set('add_trailing_slash', $addTrailingSlash);
|
||||||
|
|
||||||
|
$middleware = $this->getMockedMiddleware(false);
|
||||||
|
$middleware->setEnforceTrailingSlashConfig(true);
|
||||||
|
|
||||||
|
$requestSlash = $requestHasSlash ? '/' : '';
|
||||||
|
$noRedirectPaths = [
|
||||||
|
"/admin{$requestSlash}",
|
||||||
|
"/admin/graphql{$requestSlash}",
|
||||||
|
"/dev/tasks/my-task{$requestSlash}",
|
||||||
|
];
|
||||||
|
$allowRedirectPaths = [
|
||||||
|
"/administration{$requestSlash}",
|
||||||
|
"/administration/more-path{$requestSlash}",
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($noRedirectPaths as $path) {
|
||||||
|
$this->performRedirectTest($path, $middleware, false, $addTrailingSlash);
|
||||||
|
}
|
||||||
|
foreach ($allowRedirectPaths as $path) {
|
||||||
|
$this->performRedirectTest($path, $middleware, $addTrailingSlash !== $requestHasSlash, $addTrailingSlash);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getMockedMiddleware($mockGetRedirect = true): CanonicalURLMiddleware
|
private function getMockedMiddleware($mockGetRedirect = true): CanonicalURLMiddleware
|
||||||
|
Loading…
Reference in New Issue
Block a user