{
if ($this->controller->cHash) {
$queryParams['id'] = $this->controller->id;
- $this->controller->cHash_array = $this->cacheHashCalculator->getRelevantParameters(HttpUtility::buildQueryString($queryParams));
- $cHash_calc = $this->cacheHashCalculator->calculateCacheHash($this->controller->cHash_array);
- if (!hash_equals($cHash_calc, $this->controller->cHash)) {
+ $relevantParameters = $this->cacheHashCalculator->getRelevantParameters(HttpUtility::buildQueryString($queryParams));
+ $this->controller->cHash_array = $relevantParameters;
+ $calculatedCacheHash = $this->cacheHashCalculator->calculateCacheHash($relevantParameters);
+ // cHash was given, but nothing to be calculated, so cHash is unset and all is good.
+ if (empty($relevantParameters)) {
+ $this->getTimeTracker()->setTSlogMessage('The incoming cHash "' . $this->controller->cHash . '" is given but not needed. cHash is unset', 2);
+ // We do not need to update the query params as everything is checked via $TSFE->cHash, see $TSFE->reqCHash()
+ $this->controller->cHash = '';
+ return true;
+ }
+ if (!hash_equals($calculatedCacheHash, $this->controller->cHash)) {
// Early return to trigger the error controller
if ($pageNotFoundOnCacheHashError) {
return false;
}
$this->controller->no_cache = true;
- $this->getTimeTracker()->setTSlogMessage('The incoming cHash "' . $this->controller->cHash . '" and calculated cHash "' . $cHash_calc . '" did not match, so caching was disabled. The fieldlist used was "' . implode(',', array_keys($this->controller->cHash_array)) . '"', 2);
+ $this->getTimeTracker()->setTSlogMessage('The incoming cHash "' . $this->controller->cHash . '" and calculated cHash "' . $calculatedCacheHash . '" did not match, so caching was disabled. The fieldlist used was "' . implode(',', array_keys($this->controller->cHash_array)) . '"', 2);
}
// No cHash is set, check if that is correct
} elseif ($this->cacheHashCalculator->doParametersRequireCacheHash(HttpUtility::buildQueryString($queryParams))) {
--- /dev/null
+<?php
+declare(strict_types = 1);
+
+namespace TYPO3\CMS\Frontend\Tests\Unit\Middleware;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Core\Http\Response;
+use TYPO3\CMS\Core\Http\ServerRequest;
+use TYPO3\CMS\Core\Routing\PageArguments;
+use TYPO3\CMS\Core\TimeTracker\TimeTracker;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+use TYPO3\CMS\Frontend\Middleware\PageArgumentValidator;
+use TYPO3\CMS\Frontend\Middleware\PageResolver;
+use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+class PageArgumentValidatorTest extends UnitTestCase
+{
+ /**
+ * @var bool Reset singletons created by subject
+ */
+ protected $resetSingletonInstances = true;
+
+ /**
+ * @var TypoScriptFrontendController|AccessibleObjectInterface
+ */
+ protected $controller;
+
+ /**
+ * @var RequestHandlerInterface
+ */
+ protected $responseOutputHandler;
+
+ /**
+ * @var PageResolver|AccessibleObjectInterface
+ */
+ protected $subject;
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+ $timeTrackerStub = new TimeTracker(false);
+ GeneralUtility::setSingletonInstance(TimeTracker::class, $timeTrackerStub);
+ $this->controller = $this->getAccessibleMock(TypoScriptFrontendController::class, ['dummy'], [], '', false);
+
+ // A request handler which only runs through
+ $this->responseOutputHandler = new class implements RequestHandlerInterface {
+ public function handle(ServerRequestInterface $request): ResponseInterface
+ {
+ return new Response();
+ }
+ };
+ }
+
+ /**
+ * @test
+ */
+ public function givenCacheHashWithoutRequiredParametersIgnoresCacheHashAndUnsetsCacheHash(): void
+ {
+ $incomingUrl = 'https://example.com/lotus-flower/en/mr-magpie/bloom/';
+ $this->controller->id = 13;
+ $this->controller->cHash = 'XYZ';
+
+ $pageArguments = new PageArguments(13, '1', ['cHash' => 'XYZ'], ['parameter-from' => 'path']);
+
+ $request = new ServerRequest($incomingUrl, 'GET');
+ $request = $request->withAttribute('routing', $pageArguments);
+
+ $subject = new PageArgumentValidator($this->controller);
+ $response = $subject->process($request, $this->responseOutputHandler);
+ static::assertEquals(200, $response->getStatusCode());
+ static::assertEquals('', $this->controller->cHash);
+ }
+
+ /**
+ * @test
+ */
+ public function givenCacheHashNotMatchingCalculatedCacheHashTriggers404(): void
+ {
+ $incomingUrl = 'https://example.com/lotus-flower/en/mr-magpie/bloom/';
+ $this->controller->id = 13;
+ $this->controller->cHash = 'XYZ';
+
+ $pageArguments = new PageArguments(13, '1', ['cHash' => 'XYZ', 'dynamic' => 'argument'], ['parameter-from' => 'path']);
+
+ $request = new ServerRequest($incomingUrl, 'GET');
+ $request = $request->withAttribute('routing', $pageArguments);
+
+ $subject = new PageArgumentValidator($this->controller);
+ $response = $subject->process($request, $this->responseOutputHandler);
+ static::assertEquals(404, $response->getStatusCode());
+ }
+}