Move the cache-control adjustments from RequestHandler into a middleware
authorTim Düsterhus <duesterhus@woltlab.com>
Thu, 19 May 2022 14:09:25 +0000 (16:09 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Fri, 20 May 2022 07:22:22 +0000 (09:22 +0200)
wcfsetup/install/files/lib/http/middleware/EnforceCacheControlPrivate.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/system/request/RequestHandler.class.php

diff --git a/wcfsetup/install/files/lib/http/middleware/EnforceCacheControlPrivate.class.php b/wcfsetup/install/files/lib/http/middleware/EnforceCacheControlPrivate.class.php
new file mode 100644 (file)
index 0000000..217d1d0
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+
+namespace wcf\http\middleware;
+
+use GuzzleHttp\Psr7\Header;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use wcf\http\LegacyPlaceholderResponse;
+
+/**
+ * Adds 'private' to the 'cache-control' response header and removes 'public'.
+ *
+ * @author  Tim Duesterhus
+ * @copyright   2001-2022 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Http\Middleware
+ * @since   5.6
+ */
+final class EnforceCacheControlPrivate implements MiddlewareInterface
+{
+    /**
+     * @inheritDoc
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        $response = $handler->handle($request);
+
+        if ($response instanceof LegacyPlaceholderResponse) {
+            return $response;
+        }
+
+        // Storing responses in a shared cache is unsafe, because they all contain session specific information.
+        // Add the 'private' value to the cache-control header and remove any 'public' value.
+        $cacheControl = [
+            'private',
+        ];
+        foreach (Header::normalize($response->getHeader('cache-control')) as $value) {
+            [$field] = \explode('=', $value, 2);
+
+            // Prevent duplication of the 'private' field.
+            if ($field === 'private') {
+                continue;
+            }
+
+            // Drop the 'public' field.
+            if ($field === 'public') {
+                continue;
+            }
+
+            $cacheControl[] = $value;
+        }
+
+        return $response->withHeader(
+            'cache-control',
+            // Manually imploding the fields is not required as per strict reading of the HTTP standard,
+            // but having duplicate 'cache-control' headers in the response certainly looks odd.
+            \implode(', ', $cacheControl)
+        );
+    }
+}
index 1de1d9aa602a1f869531dbd7444907e8fa0ba810..a479f397505e47da4faa0ff868da661ec04402ca 100644 (file)
@@ -2,11 +2,11 @@
 
 namespace wcf\system\request;
 
-use GuzzleHttp\Psr7\Header;
 use Laminas\Diactoros\ServerRequestFactory;
 use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
 use Psr\Http\Message\ResponseInterface;
 use wcf\http\LegacyPlaceholderResponse;
+use wcf\http\middleware\EnforceCacheControlPrivate;
 use wcf\http\Pipeline;
 use wcf\system\application\ApplicationHandler;
 use wcf\system\box\BoxHandler;
@@ -104,7 +104,9 @@ class RequestHandler extends SingletonFactory
                 \header('cross-origin-resource-policy: same-site');
             }
 
-            $pipeline = new Pipeline([]);
+            $pipeline = new Pipeline([
+                new EnforceCacheControlPrivate(),
+            ]);
 
             $this->sendPsr7Response(
                 $pipeline->process($psrRequest, $this->getActiveRequest())
@@ -125,34 +127,6 @@ class RequestHandler extends SingletonFactory
             return;
         }
 
-        // Storing responses in a shared cache is unsafe, because they all contain session specific information.
-        // Add the 'private' value to the cache-control header and remove any 'public' value.
-        $cacheControl = [
-            'private',
-        ];
-        foreach (Header::normalize($response->getHeader('cache-control')) as $value) {
-            [$field] = \explode('=', $value, 2);
-
-            // Prevent duplication of the 'private' field.
-            if ($field === 'private') {
-                continue;
-            }
-
-            // Drop the 'public' field.
-            if ($field === 'public') {
-                continue;
-            }
-
-            $cacheControl[] = $value;
-        }
-
-        $response = $response->withHeader(
-            'cache-control',
-            // Manually imploding the fields is not required as per strict reading of the HTTP standard,
-            // but having duplicate 'cache-control' headers in the response certainly looks odd.
-            \implode(', ', $cacheControl)
-        );
-
         $response->withHeader('x-frame-options', 'SAMEORIGIN');
 
         $emitter = new SapiEmitter();