Skip to content
Snippets Groups Projects
Commit 956bb21a authored by Oliver Hader's avatar Oliver Hader Committed by Oliver Hader
Browse files

[TASK] Allow in-memory caching of HTML sanitizer behavior

DefaultSanitizerBuilder for HTML sanitizer creates a new behavior
for each invocation which is superfluous and can be cached in memory.

Resolves: #96862
Releases: main, 11.5, 10.4
Change-Id: I4a6710524a1f2f1256c8aa7694ceaa56a627a07f
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/73459


Tested-by: default avatarcore-ci <typo3@b13.com>
Tested-by: default avatarBenni Mack <benni@typo3.org>
Tested-by: default avatarOliver Hader <oliver.hader@typo3.org>
Reviewed-by: default avatarBenni Mack <benni@typo3.org>
Reviewed-by: default avatarOliver Hader <oliver.hader@typo3.org>
parent bd6006c2
Branches
Tags
No related merge requests found
......@@ -14,6 +14,7 @@ declare(strict_types=1);
namespace TYPO3\CMS\Core\Html;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\PathUtility;
use TYPO3\HtmlSanitizer\Behavior;
......@@ -27,8 +28,10 @@ use TYPO3\HtmlSanitizer\Visitor\CommonVisitor;
*
* @internal
*/
class DefaultSanitizerBuilder extends CommonBuilder
class DefaultSanitizerBuilder extends CommonBuilder implements SingletonInterface
{
private Behavior $behavior;
public function __construct()
{
parent::__construct();
......@@ -60,7 +63,9 @@ class DefaultSanitizerBuilder extends CommonBuilder
protected function createBehavior(): Behavior
{
return parent::createBehavior()
->withName('default');
if (!isset($this->behavior)) {
$this->behavior = parent::createBehavior()->withName('default');
}
return $this->behavior;
}
}
......@@ -17,7 +17,12 @@ declare(strict_types=1);
namespace TYPO3\CMS\Core\Tests\Functional\Html;
use TYPO3\CMS\Core\Html\DefaultSanitizerBuilder;
use TYPO3\CMS\Core\Html\SanitizerBuilderFactory;
use TYPO3\CMS\Core\Tests\Functional\Html\Fixtures\ExtendedSanitizerBuilder;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\HtmlSanitizer\Behavior;
use TYPO3\HtmlSanitizer\Sanitizer;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
class DefaultSanitizerBuilderTest extends FunctionalTestCase
......@@ -136,4 +141,46 @@ class DefaultSanitizerBuilderTest extends FunctionalTestCase
$sanitizer = $builder->build();
self::assertSame($expectation, $sanitizer->sanitize($payload));
}
/**
* @test
*/
public function behaviorIsCachedInMemory(): void
{
$default = GeneralUtility::makeInstance(DefaultSanitizerBuilder::class);
$defaultSanitizer = $default->build();
$defaultBehavior = $this->resolveBehaviorFromSanitizer($defaultSanitizer);
self::assertSame(
$defaultBehavior,
$this->resolveBehaviorFromSanitizer($default->build()),
'in-memory caching failed for same scope DefaultSanitizerBuilder'
);
$extended = GeneralUtility::makeInstance(ExtendedSanitizerBuilder::class);
$extendedSanitizer = $extended->build();
$extendedBehavior = $this->resolveBehaviorFromSanitizer($extendedSanitizer);
self::assertSame(
$extendedBehavior,
$this->resolveBehaviorFromSanitizer($extended->build()),
'in-memory caching failed for same scope ExtendedSanitizerBuilder'
);
self::assertNotSame(
$defaultBehavior,
$extendedBehavior,
'in-memory cache violation for different scopes'
);
}
private function resolveBehaviorFromSanitizer(Sanitizer $sanitizer): Behavior
{
$visitor = (new \ReflectionObject($sanitizer))
->getProperty('visitors')
->getValue($sanitizer)[0];
return (new \ReflectionObject($visitor))
->getProperty('behavior')
->getValue($visitor);
}
}
<?php
declare(strict_types=1);
/*
* 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!
*/
namespace TYPO3\CMS\Core\Tests\Functional\Html\Fixtures;
use TYPO3\CMS\Core\Html\DefaultSanitizerBuilder;
/**
* Extends default builder, just to ensure internal behavior
* is cached in-memory for corresponding class scope.
*/
class ExtendedSanitizerBuilder extends DefaultSanitizerBuilder
{
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment