From 88122436e5eaca2e29354d41f2981f853ed8f5d9 Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Mon, 15 Nov 2021 21:13:35 +0100
Subject: [PATCH] [BUGFIX] Make external page error handling work again

In recent TYPO3 v11.5.x versions, the error handling for Frontend
pages did cache the external PSR-7 Response (by guzzle) in the
pages cache. However, if the error page was fetched the second time,
the Response object from the cache did not have a valid stream anymore,
thus resulting in an array.

This change now caches the body + headers for the page (still, only
when a 200 response code was returned), and re-builds a clean Response
object.

Resolves: #95940
Related: #95586
Related: #94402
Releases: master
Change-Id: I27aaffe8acda275fd3450f9479e19a3f21d22df6
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/72184
Tested-by: core-ci <typo3@b13.com>
Tested-by: Oliver Bartsch <bo@cedev.de>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Oliver Bartsch <bo@cedev.de>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
---
 .../PageContentErrorHandler.php               | 24 +++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/typo3/sysext/core/Classes/Error/PageErrorHandler/PageContentErrorHandler.php b/typo3/sysext/core/Classes/Error/PageErrorHandler/PageContentErrorHandler.php
index e1015c9e2048..aaab8091dd23 100644
--- a/typo3/sysext/core/Classes/Error/PageErrorHandler/PageContentErrorHandler.php
+++ b/typo3/sysext/core/Classes/Error/PageErrorHandler/PageContentErrorHandler.php
@@ -26,6 +26,8 @@ use TYPO3\CMS\Core\Configuration\Features;
 use TYPO3\CMS\Core\Exception\SiteNotFoundException;
 use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\RequestFactory;
+use TYPO3\CMS\Core\Http\Response;
+use TYPO3\CMS\Core\Http\Stream;
 use TYPO3\CMS\Core\Http\Uri;
 use TYPO3\CMS\Core\LinkHandling\LinkService;
 use TYPO3\CMS\Core\Routing\InvalidRouteArgumentsException;
@@ -138,10 +140,9 @@ class PageContentErrorHandler implements PageErrorHandlerInterface
     protected function cachePageRequest(string $resolvedUrl, int $pageId, callable $fetcher): ResponseInterface
     {
         $cacheIdentifier = 'errorPage_' . md5($resolvedUrl);
-        /** @var ResponseInterface $response */
-        $response = $this->cache->get($cacheIdentifier);
+        $responseData = $this->cache->get($cacheIdentifier);
 
-        if (!$response) {
+        if (!is_array($responseData)) {
             /** @var ResponseInterface $response */
             $response = $fetcher();
             $cacheTags = [];
@@ -151,8 +152,23 @@ class PageContentErrorHandler implements PageErrorHandlerInterface
                     // Cache Tag "pageId_" ensures, cache is purged when content of 404 page changes
                     $cacheTags[] = 'pageId_' . $pageId;
                 }
-                $this->cache->set($cacheIdentifier, $response, $cacheTags);
+                $responseData = [
+                    'headers' => $response->getHeaders(),
+                    'body' => $response->getBody()->getContents(),
+                    'reasonPhrase' => $response->getReasonPhrase(),
+                ];
+                $this->cache->set($cacheIdentifier, $responseData, $cacheTags);
             }
+        } else {
+            $body = new Stream('php://temp', 'wb+');
+            $body->write($responseData['body'] ?? '');
+            $body->rewind();
+            $response = new Response(
+                $body,
+                200,
+                $responseData['headers'] ?? [],
+                $responseData['reasonPhrase'] ?? ''
+            );
         }
 
         return $response;
-- 
GitLab