504 errorcode 106 until that key is purged, while the origin * serves the same bytes in under 100ms). For an image that degrades one element; for * js/main..js it would take every visitor's JavaScript down. * * typo3temp is scoped to generated images on purpose - assets/compressed holds other * extensions' concatenated css/js, which belongs on the origin for the same reason. * The quote character is captured rather than matched literally, so url() values * written with single quotes are rewritten too. * * Registered after the page resolver, so the /api/* responses of ep_products never pass here. */ final class CdnImageMiddleware implements MiddlewareInterface { private const PATTERN = '/(["\'])\/?(fileadmin|uploads|typo3temp\/assets\/(?:_processed_|images))/'; public function __construct(private readonly ExtensionConfiguration $extensionConfiguration) { } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $response = $handler->handle($request); $cdnBaseUrl = rtrim((string)($this->extensionConfiguration->get('ep_theme', 'cdnBaseUrl') ?? ''), '/'); $contentType = $response->getHeaderLine('Content-Type'); if ($cdnBaseUrl === '' || !(str_starts_with($contentType, 'text/html') || str_starts_with($contentType, 'application/json')) ) { return $response; } $body = (string)$response->getBody(); $replaced = preg_replace(self::PATTERN, '$1' . $cdnBaseUrl . '/$2', $body); if ($replaced === null || $replaced === $body) { return $response; } $stream = new Stream('php://temp', 'rw'); $stream->write($replaced); return $response->withBody($stream); } }