Add `CheckForOfflineMode` middleware
authorTim Düsterhus <duesterhus@woltlab.com>
Fri, 20 May 2022 07:49:02 +0000 (09:49 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Fri, 20 May 2022 08:02:05 +0000 (10:02 +0200)
wcfsetup/install/files/lib/http/middleware/CheckForOfflineMode.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/CheckForOfflineMode.class.php b/wcfsetup/install/files/lib/http/middleware/CheckForOfflineMode.class.php
new file mode 100644 (file)
index 0000000..47ef960
--- /dev/null
@@ -0,0 +1,87 @@
+<?php
+
+namespace wcf\http\middleware;
+
+use Laminas\Diactoros\Response\HtmlResponse;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use wcf\system\box\BoxHandler;
+use wcf\system\exception\AJAXException;
+use wcf\system\notice\NoticeHandler;
+use wcf\system\request\RequestHandler;
+use wcf\system\WCF;
+use wcf\util\HeaderUtil;
+
+/**
+ * Checks whether the offline mode is enabled and the request must be intercepted.
+ *
+ * @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 CheckForOfflineMode implements MiddlewareInterface
+{
+    /**
+     * @inheritDoc
+     */
+    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+    {
+        if (
+            !$this->offlineModeEnabled()
+            || RequestHandler::getInstance()->isACPRequest()
+            || $this->userCanBypassOfflineMode()
+        ) {
+            return $handler->handle($request);
+        }
+
+        if (RequestHandler::getInstance()->getActiveRequest()->isAvailableDuringOfflineMode()) {
+            return $handler->handle($request);
+        }
+
+        return HeaderUtil::withNoCacheHeaders($this->getOfflineResponse($request));
+    }
+
+    private function getOfflineResponse(ServerRequestInterface $request): ResponseInterface
+    {
+        if ($this->isAjaxRequest($request)) {
+            throw new AJAXException(
+                WCF::getLanguage()->getDynamicVariable('wcf.ajax.error.permissionDenied'),
+                AJAXException::INSUFFICIENT_PERMISSIONS
+            );
+        } else {
+            BoxHandler::disablePageLayout();
+            NoticeHandler::disableNotices();
+
+            return new HtmlResponse(
+                WCF::getTPL()->fetchStream(
+                    'offline',
+                    'wcf',
+                    [
+                        'templateName' => 'offline',
+                        'templateNameApplication' => 'wcf',
+                    ]
+                ),
+                503
+            );
+        }
+    }
+
+    private function offlineModeEnabled(): bool
+    {
+        return \defined('OFFLINE') && OFFLINE;
+    }
+
+    private function userCanBypassOfflineMode(): bool
+    {
+        return WCF::getSession()->getPermission('admin.general.canViewPageDuringOfflineMode');
+    }
+
+    private function isAjaxRequest(ServerRequestInterface $request): bool
+    {
+        return $request->getHeaderLine('x-requested-with') === 'XMLHttpRequest';
+    }
+}
index 819dd3c6bfd634fa6ecaf6148929d15931e44834..b426b354e80c046b04f7538e3cea127020f46d19 100644 (file)
@@ -6,16 +6,15 @@ use Laminas\Diactoros\ServerRequestFactory;
 use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
 use wcf\http\LegacyPlaceholderResponse;
 use wcf\http\middleware\AddAcpSecurityHeaders;
+use wcf\http\middleware\CheckForOfflineMode;
 use wcf\http\middleware\EnforceCacheControlPrivate;
 use wcf\http\middleware\EnforceFrameOptions;
 use wcf\http\Pipeline;
 use wcf\system\application\ApplicationHandler;
-use wcf\system\box\BoxHandler;
 use wcf\system\exception\AJAXException;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\NamedUserException;
 use wcf\system\exception\SystemException;
-use wcf\system\notice\NoticeHandler;
 use wcf\system\SingletonFactory;
 use wcf\system\WCF;
 use wcf\util\FileUtil;
@@ -97,12 +96,11 @@ class RequestHandler extends SingletonFactory
 
             $this->checkAppEvaluation();
 
-            $this->checkOfflineMode();
-
             $pipeline = new Pipeline([
                 new AddAcpSecurityHeaders(),
                 new EnforceCacheControlPrivate(),
                 new EnforceFrameOptions(),
+                new CheckForOfflineMode(),
             ]);
 
             $response = $pipeline->process($psrRequest, $this->getActiveRequest());
@@ -251,40 +249,6 @@ class RequestHandler extends SingletonFactory
         }
     }
 
-    /**
-     * @since 5.5
-     */
-    private function checkOfflineMode()
-    {
-        if (!$this->isACPRequest() && \defined('OFFLINE') && OFFLINE) {
-            if (
-                !WCF::getSession()->getPermission('admin.general.canViewPageDuringOfflineMode')
-                && !$this->getActiveRequest()->isAvailableDuringOfflineMode()
-            ) {
-                if (
-                    isset($_SERVER['HTTP_X_REQUESTED_WITH'])
-                    && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest')
-                ) {
-                    throw new AJAXException(
-                        WCF::getLanguage()->getDynamicVariable('wcf.ajax.error.permissionDenied'),
-                        AJAXException::INSUFFICIENT_PERMISSIONS
-                    );
-                } else {
-                    @\header('HTTP/1.1 503 Service Unavailable');
-                    BoxHandler::disablePageLayout();
-                    NoticeHandler::disableNotices();
-                    WCF::getTPL()->assign([
-                        'templateName' => 'offline',
-                        'templateNameApplication' => 'wcf',
-                    ]);
-                    WCF::getTPL()->display('offline');
-                }
-
-                exit;
-            }
-        }
-    }
-
     /**
      * @since 5.5
      */