From e487cf526980570aa8f7a92d170bf439637c5972 Mon Sep 17 00:00:00 2001
From: Christian Kuhn <lolli@schwarzbu.ch>
Date: Fri, 16 Feb 2018 14:03:09 +0100
Subject: [PATCH] [TASK] Create own response instance in controller actions

To further support the PSR-7 / PSR-15 and removal of
GeneralUtility::_GP() and friends efforts, all controllers
no longer use the second 'ResponseInterface $response'
argument given by dispatchers: Dispatchers should not
assume which type of response a controller returns, there
is no point in preparing this object.

Instead, controllers now always create one of
HtmlResponse, JsonResponse or RedirectResponse on
their own and return these objects.

Changes overview:
* Always use "new" to instantiate a response, PSR-15
  middlewares allow fiddling with the object if needed,
  xclassing these classes is never needed, we instead
  can rely on proper API usage.
* All controller actions drop the second $response argument
  and add ResponseInterface return type hint.
* Some controllers action also drop first $request argument,
  but only if the action does not need access to ServerParams
  at all. Those controllers that access _GP or _POST or similar
  currently, keep $request for now - they have to be refactored
  later anyway and then need $request.

Change-Id: Icce283b3c19be14ef1adeec761cfd63c90ab24c5
Resolves: #83939
Releases: master
Reviewed-on: https://review.typo3.org/55754
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Benjamin Kott <benjamin.kott@outlook.com>
Tested-by: Benjamin Kott <benjamin.kott@outlook.com>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
---
 .../Classes/Controller/AboutController.php    |   4 +-
 .../ToolbarItems/ShortcutToolbarItem.php      | 147 ++++++++----------
 .../SystemInformationToolbarItem.php          |  19 ++-
 .../Controller/AjaxLoginController.php        |   9 +-
 .../Classes/Controller/BackendController.php  |  19 +--
 .../ElementHistoryController.php              |   7 +-
 .../ElementInformationController.php          |   8 +-
 .../ContentElement/MoveElementController.php  |   8 +-
 .../NewContentElementController.php           |  13 +-
 .../Controller/ContextHelpAjaxController.php  |  20 +--
 .../Controller/ContextMenuController.php      |   4 +-
 .../Classes/Controller/DummyController.php    |  45 ++----
 .../Controller/EditDocumentController.php     |   7 +-
 .../File/CreateFolderController.php           |   7 +-
 .../Controller/File/EditFileController.php    |   8 +-
 .../Controller/File/FileController.php        |  52 +++----
 .../Controller/File/FileUploadController.php  |   8 +-
 .../Controller/File/RenameFileController.php  |   8 +-
 .../Controller/File/ReplaceFileController.php |   8 +-
 .../FileSystemNavigationFrameController.php   |  15 +-
 .../Controller/FlashMessageController.php     |   6 +-
 .../Controller/FormFlexAjaxController.php     |   2 +-
 .../Controller/FormInlineAjaxController.php   |   8 +-
 .../FormSelectTreeAjaxController.php          |   2 +-
 .../Controller/LinkBrowserController.php      |   2 +-
 .../Controller/LiveSearchController.php       |   2 +-
 .../Classes/Controller/LoginController.php    |   8 +-
 .../Controller/LoginFramesetController.php    |   7 +-
 .../Classes/Controller/LogoutController.php   |  12 +-
 .../Controller/NewRecordController.php        |   8 +-
 .../Controller/OnlineMediaController.php      |  11 +-
 .../Page/LocalizationController.php           |  29 ++--
 .../Page/NewMultiplePagesController.php       |  10 +-
 .../Page/SortSubPagesController.php           |  10 +-
 .../Controller/Page/TreeController.php        |   6 +-
 .../Controller/PageLayoutController.php       |   7 +-
 .../SimpleDataHandlerController.php           |  13 +-
 .../Controller/UserSettingsController.php     |   2 +-
 .../Controller/Wizard/AddController.php       |   6 +-
 .../Controller/Wizard/EditController.php      |   7 +-
 .../Controller/Wizard/ListController.php      |   6 +-
 .../Wizard/SuggestWizardController.php        |   2 +-
 .../Controller/Wizard/TableController.php     |   7 +-
 .../Form/Wizard/ImageManipulationWizard.php   |  10 +-
 .../FormInlineAjaxControllerTest.php          |  28 ++--
 .../FormSelectTreeAjaxControllerTest.php      |   7 +-
 .../Wizard/SuggestWizardControllerTest.php    |   7 +-
 .../Controller/PermissionAjaxController.php   |   9 +-
 .../Classes/Controller/FileDumpController.php |   6 +-
 .../core/Classes/Imaging/IconFactory.php      |  12 +-
 .../Classes/Controller/DocumentController.php |   5 +-
 .../Controller/ShowImageController.php        |  11 +-
 .../Controller/ImportExportController.php     |   8 +-
 .../Controller/InfoModuleController.php       |   7 +-
 .../Controller/BackendModuleController.php    |  17 +-
 .../Controller/ConfigurationController.php    |   7 +-
 .../DatabaseIntegrityController.php           |   7 +-
 .../ToolbarItems/OpendocsToolbarItem.php      |  13 +-
 .../AbstractLinkBrowserController.php         |   7 +-
 .../Controller/ElementBrowserController.php   |  15 +-
 .../ElementBrowserFramesetController.php      |   8 +-
 .../sysext/recordlist/Classes/RecordList.php  |   7 +-
 .../Controller/RecyclerAjaxController.php     |   4 +-
 .../RsaPublicKeyGenerationController.php      |   9 +-
 .../rsaauth/Classes/RsaEncryptionEncoder.php  |  24 ++-
 .../Controller/SchedulerModuleController.php  |   7 +-
 .../Controller/SetupModuleController.php      |   8 +-
 .../t3editor/Classes/CodeCompletion.php       |  22 +--
 .../Classes/TypoScriptReferenceLoader.php     |   2 +-
 .../Controller/TaskModuleController.php       |   8 +-
 .../sysext/taskcenter/Classes/TaskStatus.php  |  11 +-
 .../TypoScriptTemplateModuleController.php    |   7 +-
 .../Classes/Controller/AjaxController.php     |   3 +-
 .../Classes/Controller/AjaxDispatcher.php     |   2 +-
 74 files changed, 358 insertions(+), 529 deletions(-)

diff --git a/typo3/sysext/about/Classes/Controller/AboutController.php b/typo3/sysext/about/Classes/Controller/AboutController.php
index 6b7d91a7c850..88452a22cd62 100644
--- a/typo3/sysext/about/Classes/Controller/AboutController.php
+++ b/typo3/sysext/about/Classes/Controller/AboutController.php
@@ -15,7 +15,6 @@ namespace TYPO3\CMS\About\Controller;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Module\ModuleLoader;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
@@ -46,10 +45,9 @@ class AboutController
     /**
      * Main action: Show standard information
      *
-     * @param ServerRequestInterface $request the incoming PSR-7 request
      * @return ResponseInterface the HTML output
      */
-    public function indexAction(ServerRequestInterface $request): ResponseInterface
+    public function indexAction(): ResponseInterface
     {
         $this->moduleTemplate = GeneralUtility::makeInstance(ModuleTemplate::class);
         $this->initializeView('index');
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
index 15bce3f834e5..6c3332d01134 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/ShortcutToolbarItem.php
@@ -23,6 +23,7 @@ use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\Connection;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\QueryHelper;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -142,8 +143,6 @@ class ShortcutToolbarItem implements ToolbarItemInterface
      * Render drop down content
      *
      * @return string HTML
-     * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidExtensionNameException
-     * @throws \InvalidArgumentException
      */
     public function getDropDown()
     {
@@ -166,17 +165,11 @@ class ShortcutToolbarItem implements ToolbarItemInterface
     /**
      * Renders the menu so that it can be returned as response to an AJAX call
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function menuAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function menuAction(): ResponseInterface
     {
-        $menuContent = $this->getDropDown();
-
-        $response->getBody()->write($menuContent);
-        $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
-        return $response;
+        return new HtmlResponse($this->getDropDown());
     }
 
     /**
@@ -442,16 +435,12 @@ class ShortcutToolbarItem implements ToolbarItemInterface
     }
 
     /**
-     * Fetches the available shortcut groups, renders a form so it can be saved later on, usually called via AJAX
+     * Fetches the available shortcut groups, renders a form so it can be saved later on, called via AJAX
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface the full HTML for the form
-     * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidExtensionNameException
-     * @throws \RuntimeException
-     * @throws \InvalidArgumentException
      */
-    public function editFormAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function editFormAction(ServerRequestInterface $request): ResponseInterface
     {
         $parsedBody = $request->getParsedBody();
         $queryParams = $request->getQueryParams();
@@ -474,8 +463,7 @@ class ShortcutToolbarItem implements ToolbarItemInterface
         $editFormView->assign('selectedShortcut', $selectedShortcut);
         $editFormView->assign('shortcutGroups', $shortcutGroups);
 
-        $response->getBody()->write($editFormView->render());
-        return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
+        return new HtmlResponse($editFormView->render());
     }
 
     /**
@@ -507,17 +495,17 @@ class ShortcutToolbarItem implements ToolbarItemInterface
                 $success = true;
             }
         }
-        return GeneralUtility::makeInstance(JsonResponse::class, ['success' => $success]);
+        return new JsonResponse(['success' => $success]);
     }
 
     /**
      * Creates a shortcut through an AJAX call
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
+     * @throws \RuntimeException
      */
-    public function createShortcutAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function createShortcutAction(ServerRequestInterface $request): ResponseInterface
     {
         $languageService = $this->getLanguageService();
         $parsedBody = $request->getParsedBody();
@@ -539,76 +527,76 @@ class ShortcutToolbarItem implements ToolbarItemInterface
         $queryParameters = GeneralUtility::explodeUrl2Array($queryParts['query'], true);
 
         // Proceed only if no scheme is defined, as URL is expected to be relative
-        if (empty($queryParts['scheme'])) {
-            if (is_array($queryParameters['edit'])) {
-                $shortcut['table'] = key($queryParameters['edit']);
-                $shortcut['recordid'] = key($queryParameters['edit'][$shortcut['table']]);
-                $shortcut['pid'] = BackendUtility::getRecord($shortcut['table'], $shortcut['recordid'])['pid'];
-                if ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] === 'edit') {
-                    $shortcut['type'] = 'edit';
-                    $shortcutNamePrepend = htmlspecialchars($languageService->getLL('shortcut_edit'));
-                } elseif ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] === 'new') {
-                    $shortcut['type'] = 'new';
-                    $shortcutNamePrepend = htmlspecialchars($languageService->getLL('shortcut_create'));
-                }
-            } else {
-                $shortcut['type'] = 'other';
-                $shortcut['table'] = '';
-                $shortcut['recordid'] = 0;
+        if (!empty($queryParameters['scheme'])) {
+            throw new \RuntimeException('relative url expected', 1518785877);
+        }
+
+        if (is_array($queryParameters['edit'])) {
+            $shortcut['table'] = key($queryParameters['edit']);
+            $shortcut['recordid'] = key($queryParameters['edit'][$shortcut['table']]);
+            $shortcut['pid'] = BackendUtility::getRecord($shortcut['table'], $shortcut['recordid'])['pid'];
+            if ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] === 'edit') {
+                $shortcut['type'] = 'edit';
+                $shortcutNamePrepend = htmlspecialchars($languageService->getLL('shortcut_edit'));
+            } elseif ($queryParameters['edit'][$shortcut['table']][$shortcut['recordid']] === 'new') {
+                $shortcut['type'] = 'new';
+                $shortcutNamePrepend = htmlspecialchars($languageService->getLL('shortcut_create'));
             }
+        } else {
+            $shortcut['type'] = 'other';
+            $shortcut['table'] = '';
+            $shortcut['recordid'] = 0;
+        }
 
-            // Check if given id is a combined identifier
-            if (!empty($queryParameters['id']) && preg_match('/^[0-9]+:/', $queryParameters['id'])) {
-                try {
-                    $resourceFactory = ResourceFactory::getInstance();
-                    $resource = $resourceFactory->getObjectFromCombinedIdentifier($queryParameters['id']);
-                    $shortcutName = trim($shortcutNamePrepend . ' ' . $resource->getName());
-                } catch (ResourceDoesNotExistException $e) {
-                }
-            } else {
-                // Lookup the title of this page and use it as default description
-                $pageId = (int)($shortcut['pid'] ?: ($shortcut['recordid'] ?: $this->getLinkedPageId($url)));
-                $page = false;
-                if ($pageId) {
-                    $page = BackendUtility::getRecord('pages', $pageId);
-                }
-                if (!empty($page)) {
-                    // Set the name to the title of the page
-                    if ($shortcut['type'] === 'other') {
-                        if (empty($shortcutName)) {
-                            $shortcutName = $page['title'];
-                        } else {
-                            $shortcutName .= ' (' . $page['title'] . ')';
-                        }
+        // Check if given id is a combined identifier
+        if (!empty($queryParameters['id']) && preg_match('/^[0-9]+:/', $queryParameters['id'])) {
+            try {
+                $resourceFactory = ResourceFactory::getInstance();
+                $resource = $resourceFactory->getObjectFromCombinedIdentifier($queryParameters['id']);
+                $shortcutName = trim($shortcutNamePrepend . ' ' . $resource->getName());
+            } catch (ResourceDoesNotExistException $e) {
+            }
+        } else {
+            // Lookup the title of this page and use it as default description
+            $pageId = (int)($shortcut['pid'] ?: ($shortcut['recordid'] ?: $this->getLinkedPageId($url)));
+            $page = false;
+            if ($pageId) {
+                $page = BackendUtility::getRecord('pages', $pageId);
+            }
+            if (!empty($page)) {
+                // Set the name to the title of the page
+                if ($shortcut['type'] === 'other') {
+                    if (empty($shortcutName)) {
+                        $shortcutName = $page['title'];
                     } else {
-                        $shortcutName = $shortcutNamePrepend . ' ' .
-                            $languageService->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']) .
-                            ' (' . $page['title'] . ')';
+                        $shortcutName .= ' (' . $page['title'] . ')';
                     }
-                } elseif ($shortcut['table'] !== '' && $shortcut['type'] !== 'other') {
+                } else {
                     $shortcutName = $shortcutNamePrepend . ' ' .
-                        $languageService->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']);
+                        $languageService->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']) .
+                        ' (' . $page['title'] . ')';
                 }
+            } elseif ($shortcut['table'] !== '' && $shortcut['type'] !== 'other') {
+                $shortcutName = $shortcutNamePrepend . ' ' .
+                    $languageService->sL($GLOBALS['TCA'][$shortcut['table']]['ctrl']['title']);
             }
-
-            return $this->tryAddingTheShortcut($response, $url, $shortcutName);
         }
+
+        $shortcutCreated = $this->tryAddingTheShortcut($parsedBody['module'], $url, $shortcutName);
+        return new HtmlResponse($shortcutCreated);
     }
 
     /**
      * Try to adding a shortcut
      *
-     * @param ResponseInterface $response
+     * @param string $module
      * @param string $url
      * @param string $shortcutName
-     * @return ResponseInterface
-     * @throws \InvalidArgumentException
+     * @return string
      */
-    protected function tryAddingTheShortcut(ResponseInterface $response, $url, $shortcutName)
+    protected function tryAddingTheShortcut(string $module, $url, $shortcutName): string
     {
-        $module = GeneralUtility::_POST('module');
         $shortcutCreated = 'failed';
-
         if (!empty($module) && !empty($url)) {
             $shortcutCreated = 'alreadyExists';
 
@@ -616,9 +604,7 @@ class ShortcutToolbarItem implements ToolbarItemInterface
                 $shortcutCreated = $this->addShortcut($url, $shortcutName, $module);
             }
         }
-
-        $response->getBody()->write($shortcutCreated);
-        return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
+        return $shortcutCreated;
     }
 
     /**
@@ -690,10 +676,9 @@ class ShortcutToolbarItem implements ToolbarItemInterface
      * permissions to do so and saves the changes if everything is ok
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function saveFormAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function saveFormAction(ServerRequestInterface $request): ResponseInterface
     {
         $parsedBody = $request->getParsedBody();
         $queryParams = $request->getQueryParams();
@@ -730,11 +715,9 @@ class ShortcutToolbarItem implements ToolbarItemInterface
         }
 
         if ($queryBuilder->execute() === 1) {
-            $response->getBody()->write($shortcutName);
-        } else {
-            $response->getBody()->write('failed');
+            return new HtmlResponse($shortcutName);
         }
-        return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
+        return new HtmlResponse('failed');
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php b/typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php
index c57201af0d8e..c4eed8bef763 100644
--- a/typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php
+++ b/typo3/sysext/backend/Classes/Backend/ToolbarItems/SystemInformationToolbarItem.php
@@ -15,18 +15,20 @@ namespace TYPO3\CMS\Backend\Backend\ToolbarItems;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Toolbar\Enumeration\InformationStatus;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 use TYPO3\CMS\Core\Core\Bootstrap;
 use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\CommandUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\StringUtility;
 use TYPO3\CMS\Core\Utility\VersionNumberUtility;
+use TYPO3\CMS\Extbase\Object\ObjectManager;
+use TYPO3\CMS\Extbase\SignalSlot\Dispatcher;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
 /**
@@ -66,7 +68,7 @@ class SystemInformationToolbarItem implements ToolbarItemInterface
     protected $systemMessages = [];
 
     /**
-     * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     * @var Dispatcher
      */
     protected $signalSlotDispatcher = null;
 
@@ -107,15 +109,12 @@ class SystemInformationToolbarItem implements ToolbarItemInterface
     /**
      * Renders the menu for AJAX calls
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function renderMenuAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function renderMenuAction(): ResponseInterface
     {
         $this->collectInformation();
-        $response->getBody()->write($this->getDropDown());
-        return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
+        return new HtmlResponse($this->getDropDown());
     }
 
     /**
@@ -411,13 +410,13 @@ class SystemInformationToolbarItem implements ToolbarItemInterface
     /**
      * Get the SignalSlot dispatcher
      *
-     * @return \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
+     * @return Dispatcher
      */
     protected function getSignalSlotDispatcher()
     {
         if (!isset($this->signalSlotDispatcher)) {
-            $this->signalSlotDispatcher = GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class)
-                ->get(\TYPO3\CMS\Extbase\SignalSlot\Dispatcher::class);
+            $this->signalSlotDispatcher = GeneralUtility::makeInstance(ObjectManager::class)
+                ->get(Dispatcher::class);
         }
         return $this->signalSlotDispatcher;
     }
diff --git a/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php b/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php
index 2a0996b4fa65..5f4e916c7248 100644
--- a/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php
+++ b/typo3/sysext/backend/Classes/Controller/AjaxLoginController.php
@@ -19,7 +19,6 @@ use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
 use TYPO3\CMS\Core\Http\JsonResponse;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * This is the ajax handler for backend login after timeout.
@@ -49,7 +48,7 @@ class AjaxLoginController
         } else {
             $result = ['success' => false];
         }
-        return GeneralUtility::makeInstance(JsonResponse::class, ['login' => $result]);
+        return new JsonResponse(['login' => $result]);
     }
 
     /**
@@ -62,7 +61,7 @@ class AjaxLoginController
     {
         $backendUser = $this->getBackendUser();
         $backendUser->logoff();
-        return GeneralUtility::makeInstance(JsonResponse::class, [
+        return new JsonResponse([
             'logout' => [
                 'success' => !isset($backendUser->user['uid'])
             ]
@@ -78,7 +77,7 @@ class AjaxLoginController
     public function refreshAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->getBackendUser()->checkAuthentication();
-        return GeneralUtility::makeInstance(JsonResponse::class, [
+        return new JsonResponse([
             'refresh' => [
                 'success' => true
             ]
@@ -111,7 +110,7 @@ class AjaxLoginController
             // 120 is somewhat arbitrary to allow for a little room during the countdown and load times, etc.
             $session['will_time_out'] = $GLOBALS['EXEC_TIME'] >= $ses_tstamp + $timeout - 120;
         }
-        return GeneralUtility::makeInstance(JsonResponse::class, ['login' => $session]);
+        return new JsonResponse(['login' => $session]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/BackendController.php b/typo3/sysext/backend/Classes/Controller/BackendController.php
index 8b9185772b98..140b5ebb0469 100644
--- a/typo3/sysext/backend/Classes/Controller/BackendController.php
+++ b/typo3/sysext/backend/Classes/Controller/BackendController.php
@@ -15,7 +15,6 @@ namespace TYPO3\CMS\Backend\Controller;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Domain\Repository\Module\BackendModuleRepository;
 use TYPO3\CMS\Backend\Module\ModuleLoader;
 use TYPO3\CMS\Backend\Routing\UriBuilder;
@@ -25,6 +24,7 @@ use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Page\PageRenderer;
@@ -224,15 +224,12 @@ class BackendController
      * Injects the request object for the current request or subrequest
      * As this controller goes only through the render() method, it is rather simple for now
      *
-     * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(): ResponseInterface
     {
         $this->render();
-        $response->getBody()->write($this->content);
-        return $response;
+        return new HtmlResponse($this->content);
     }
 
     /**
@@ -588,23 +585,21 @@ class BackendController
     /**
      * Returns the Module menu for the AJAX request
      *
-     * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function getModuleMenu(ServerRequestInterface $request): ResponseInterface
+    public function getModuleMenu(): ResponseInterface
     {
-        return GeneralUtility::makeInstance(JsonResponse::class, ['menu' => $this->generateModuleMenu()]);
+        return new JsonResponse(['menu' => $this->generateModuleMenu()]);
     }
 
     /**
      * Returns the toolbar for the AJAX request
      *
-     * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function getTopbar(ServerRequestInterface $request): ResponseInterface
+    public function getTopbar(): ResponseInterface
     {
-        return GeneralUtility::makeInstance(JsonResponse::class, ['topbar' => $this->renderTopbar()]);
+        return new JsonResponse(['topbar' => $this->renderTopbar()]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/ContentElement/ElementHistoryController.php b/typo3/sysext/backend/Classes/Controller/ContentElement/ElementHistoryController.php
index 8e5293152e45..e8fcfedadd0d 100644
--- a/typo3/sysext/backend/Classes/Controller/ContentElement/ElementHistoryController.php
+++ b/typo3/sysext/backend/Classes/Controller/ContentElement/ElementHistoryController.php
@@ -21,6 +21,7 @@ use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\History\RecordHistoryStore;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\DiffUtility;
@@ -81,10 +82,9 @@ class ElementHistoryController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->request = $request;
         $this->moduleTemplate->getDocHeaderComponent()->setMetaInformation([]);
@@ -146,8 +146,7 @@ class ElementHistoryController
         // Build the <body> for the module
         $this->moduleTemplate->setContent($this->view->render());
 
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/ContentElement/ElementInformationController.php b/typo3/sysext/backend/Classes/Controller/ContentElement/ElementInformationController.php
index 812bfd4c2ae1..e34108a54dd1 100644
--- a/typo3/sysext/backend/Classes/Controller/ContentElement/ElementInformationController.php
+++ b/typo3/sysext/backend/Classes/Controller/ContentElement/ElementInformationController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Backend\Avatar\Avatar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Resource\AbstractFile;
@@ -188,15 +189,12 @@ class ElementInformationController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/ContentElement/MoveElementController.php b/typo3/sysext/backend/Classes/Controller/ContentElement/MoveElementController.php
index 2aaca458a094..61ff8d523ef9 100644
--- a/typo3/sysext/backend/Classes/Controller/ContentElement/MoveElementController.php
+++ b/typo3/sysext/backend/Classes/Controller/ContentElement/MoveElementController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Tree\View\ContentMovingPagePositionMap;
 use TYPO3\CMS\Backend\Tree\View\PageMovingPagePositionMap;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -119,16 +120,13 @@ class MoveElementController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-
         $this->moduleTemplate->setContent($this->content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/ContentElement/NewContentElementController.php b/typo3/sysext/backend/Classes/Controller/ContentElement/NewContentElementController.php
index 52af9c1aafc9..0fb9787b4d54 100644
--- a/typo3/sysext/backend/Classes/Controller/ContentElement/NewContentElementController.php
+++ b/typo3/sysext/backend/Classes/Controller/ContentElement/NewContentElementController.php
@@ -22,6 +22,7 @@ use TYPO3\CMS\Backend\Tree\View\ContentCreationPagePositionMap;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Backend\View\BackendLayoutView;
 use TYPO3\CMS\Backend\Wizard\NewContentElementWizardHookInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Service\DependencyOrderingService;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
@@ -184,15 +185,13 @@ class NewContentElementController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->prepareContent('window');
         $this->moduleTemplate->setContent($this->content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
@@ -200,14 +199,12 @@ class NewContentElementController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function wizardAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function wizardAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->prepareContent('list_frame');
-        $response->getBody()->write($this->content);
-        return $response;
+        return new HtmlResponse($this->content);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/ContextHelpAjaxController.php b/typo3/sysext/backend/Classes/Controller/ContextHelpAjaxController.php
index 7076f1242a2f..e1af5cdf5007 100644
--- a/typo3/sysext/backend/Classes/Controller/ContextHelpAjaxController.php
+++ b/typo3/sysext/backend/Classes/Controller/ContextHelpAjaxController.php
@@ -31,21 +31,21 @@ class ContextHelpAjaxController
      * The main dispatcher function. Collect data and prepare HTML output.
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
+     * @throws \RuntimeException
      */
-    public function getHelpAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function getHelpAction(ServerRequestInterface $request): ResponseInterface
     {
         $params = $request->getParsedBody()['params'] ?? $request->getQueryParams()['params'];
-        if ($params['action'] === 'getContextHelp') {
-            $result = $this->getContextHelp($params['table'], $params['field']);
-            return GeneralUtility::makeInstance(JsonResponse::class, [
-                'title' => $result['title'],
-                'content' => $result['description'],
-                'link' => $result['moreInfo']
-            ]);
+        if ($params['action'] !== 'getContextHelp') {
+            throw new \RuntimeException('Action must be set to "getContextHelp"', 1518787887);
         }
-        return $response;
+        $result = $this->getContextHelp($params['table'], $params['field']);
+        return new JsonResponse([
+            'title' => $result['title'],
+            'content' => $result['description'],
+            'link' => $result['moreInfo']
+        ]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/ContextMenuController.php b/typo3/sysext/backend/Classes/Controller/ContextMenuController.php
index 40fb5c273192..002144f2176c 100644
--- a/typo3/sysext/backend/Classes/Controller/ContextMenuController.php
+++ b/typo3/sysext/backend/Classes/Controller/ContextMenuController.php
@@ -52,7 +52,7 @@ class ContextMenuController
         if (!is_array($items)) {
             $items = [];
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($items);
+        return (new JsonResponse())->setPayload($items);
     }
 
     /**
@@ -70,7 +70,7 @@ class ContextMenuController
         $clipboard->cleanCurrent();
 
         $clipboard->endClipboard();
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload([]);
+        return (new JsonResponse())->setPayload([]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/DummyController.php b/typo3/sysext/backend/Classes/Controller/DummyController.php
index 5635c19c8923..c1d9c9458bff 100644
--- a/typo3/sysext/backend/Classes/Controller/DummyController.php
+++ b/typo3/sysext/backend/Classes/Controller/DummyController.php
@@ -15,57 +15,30 @@ namespace TYPO3\CMS\Backend\Controller;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Template\DocumentTemplate;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 
 /**
- * Script Class, creating the content for the dummy script - which is just blank output.
+ * '/empty' routing target returns dummy content.
  */
 class DummyController
 {
     /**
-     * @var string
-     */
-    public $content;
-
-    /**
-     * Constructor
-     */
-    public function __construct()
-    {
-        $GLOBALS['SOBE'] = $this;
-    }
-
-    /**
-     * Injects the request object for the current request or subrequest
-     * As this controller goes only through the main() method, it is rather simple for now
+     * Return simple dummy content
      *
-     * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
-    {
-        $this->main();
-
-        $response->getBody()->write($this->content);
-        return $response;
-    }
-
-    /**
-     * Create content for the dummy script - outputting a blank page.
-     */
-    public function main()
+    public function mainAction(): ResponseInterface
     {
-        // Start page
-        $this->content .= $this->getDocumentTemplate()->startPage('Dummy document');
-        // End page:
-        $this->content .= $this->getDocumentTemplate()->endPage();
+        $documentTemplate = $this->getDocumentTemplate();
+        $content = $documentTemplate->startPage('Dummy document') . $documentTemplate->endPage();
+        return new HtmlResponse($content);
     }
 
     /**
      * Returns an instance of DocumentTemplate
      *
-     * @return \TYPO3\CMS\Backend\Template\DocumentTemplate
+     * @return DocumentTemplate
      */
     protected function getDocumentTemplate()
     {
diff --git a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
index cdf8e76a5720..61a646aa7c05 100644
--- a/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
+++ b/typo3/sysext/backend/Classes/Controller/EditDocumentController.php
@@ -30,6 +30,7 @@ use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageQueue;
@@ -2076,10 +2077,9 @@ class EditDocumentController
      * Injects the request object for the current request or subrequest
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         BackendUtility::lockRecords();
 
@@ -2094,8 +2094,7 @@ class EditDocumentController
         $this->init();
         $this->main();
 
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/File/CreateFolderController.php b/typo3/sysext/backend/Classes/Controller/File/CreateFolderController.php
index d095945496b1..1bc22522f6e8 100644
--- a/typo3/sysext/backend/Classes/Controller/File/CreateFolderController.php
+++ b/typo3/sysext/backend/Classes/Controller/File/CreateFolderController.php
@@ -18,6 +18,7 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
 use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
@@ -264,14 +265,12 @@ class CreateFolderController
      * Processes the request, currently everything is handled and put together via "main()"
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/File/EditFileController.php b/typo3/sysext/backend/Classes/Controller/File/EditFileController.php
index 7df8db6278d9..349ea4eacb88 100644
--- a/typo3/sysext/backend/Classes/Controller/File/EditFileController.php
+++ b/typo3/sysext/backend/Classes/Controller/File/EditFileController.php
@@ -21,6 +21,7 @@ use TYPO3\CMS\Backend\Form\NodeFactory;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
@@ -274,15 +275,12 @@ class EditFileController
      * Processes the request, currently everything is handled and put together via "main()"
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/File/FileController.php b/typo3/sysext/backend/Classes/Controller/File/FileController.php
index b8338f4fc246..372ff4238908 100644
--- a/typo3/sysext/backend/Classes/Controller/File/FileController.php
+++ b/typo3/sysext/backend/Classes/Controller/File/FileController.php
@@ -17,11 +17,14 @@ namespace TYPO3\CMS\Backend\Controller\File;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
+use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Resource\DuplicationBehavior;
 use TYPO3\CMS\Core\Resource\Folder;
+use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\File\ExtendedFileUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -164,10 +167,9 @@ class FileController
      * As this controller goes only through the main() method, it just redirects to the given URL afterwards.
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
 
@@ -189,12 +191,13 @@ class FileController
             $this->redirect = (string)$uriBuilder->buildUriFromRoute('file_edit', $urlParameters);
         }
         if ($this->redirect) {
-            return $response
-                    ->withHeader('Location', GeneralUtility::locationHeaderUrl($this->redirect))
-                    ->withStatus(303);
+            return new RedirectResponse(
+                GeneralUtility::locationHeaderUrl($this->redirect),
+                303
+            );
         }
         // empty response
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
@@ -204,34 +207,28 @@ class FileController
      * actual return value
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function processAjaxRequest(ServerRequestInterface $request, ResponseInterface $response)
+    public function processAjaxRequest(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
         $errors = $this->fileProcessor->getErrorMessages();
         if (!empty($errors)) {
-            $response->getBody()->write('<t3err>' . implode(',', $errors) . '</t3err>');
-            $response = $response
-                ->withHeader('Content-Type', 'text/html; charset=utf-8')
-                ->withStatus(500, '(AJAX)');
-        } else {
-            $flatResult = [];
-            foreach ($this->fileData as $action => $results) {
-                foreach ($results as $result) {
-                    if (is_array($result)) {
-                        foreach ($result as $subResult) {
-                            $flatResult[$action][] = $this->flattenResultDataValue($subResult);
-                        }
-                    } else {
-                        $flatResult[$action][] = $this->flattenResultDataValue($result);
+            return (new HtmlResponse('<t3err>' . implode(',', $errors) . '</t3err>'))->withStatus(500, '(AJAX)');
+        }
+        $flatResult = [];
+        foreach ($this->fileData as $action => $results) {
+            foreach ($results as $result) {
+                if (is_array($result)) {
+                    foreach ($result as $subResult) {
+                        $flatResult[$action][] = $this->flattenResultDataValue($subResult);
                     }
+                } else {
+                    $flatResult[$action][] = $this->flattenResultDataValue($result);
                 }
             }
-            return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($flatResult);
         }
-        return $response;
+        return (new JsonResponse())->setPayload($flatResult);
     }
 
     /**
@@ -240,13 +237,12 @@ class FileController
      * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function fileExistsInFolderAction(ServerRequestInterface $request)
+    public function fileExistsInFolderAction(ServerRequestInterface $request): ResponseInterface
     {
         $fileName = $request->getParsedBody()['fileName'] ?? $request->getQueryParams()['fileName'];
         $fileTarget = $request->getParsedBody()['fileTarget'] ?? $request->getQueryParams()['fileTarget'];
 
-        /** @var \TYPO3\CMS\Core\Resource\ResourceFactory $fileFactory */
-        $fileFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\ResourceFactory::class);
+        $fileFactory = GeneralUtility::makeInstance(ResourceFactory::class);
         /** @var Folder $fileTargetObject */
         $fileTargetObject = $fileFactory->retrieveFileOrFolderObject($fileTarget);
         $processedFileName = $fileTargetObject->getStorage()->sanitizeFileName($fileName, $fileTargetObject);
@@ -255,7 +251,7 @@ class FileController
         if ($fileTargetObject->hasFile($processedFileName)) {
             $result = $this->flattenResultDataValue($fileTargetObject->getStorage()->getFileInFolder($processedFileName, $fileTargetObject));
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($result);
+        return (new JsonResponse())->setPayload($result);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/File/FileUploadController.php b/typo3/sysext/backend/Classes/Controller/File/FileUploadController.php
index f1e73b5ee600..0bbd63e81914 100644
--- a/typo3/sysext/backend/Classes/Controller/File/FileUploadController.php
+++ b/typo3/sysext/backend/Classes/Controller/File/FileUploadController.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Controller\File;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
@@ -210,15 +211,12 @@ class FileUploadController
      * Processes the request, currently everything is handled and put together via "main()"
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/File/RenameFileController.php b/typo3/sysext/backend/Classes/Controller/File/RenameFileController.php
index d5fa13f3dcf8..21f2992cf7ee 100644
--- a/typo3/sysext/backend/Classes/Controller/File/RenameFileController.php
+++ b/typo3/sysext/backend/Classes/Controller/File/RenameFileController.php
@@ -18,6 +18,7 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Resource\DuplicationBehavior;
 use TYPO3\CMS\Core\Resource\File;
@@ -218,15 +219,12 @@ class RenameFileController
     /**
      * Processes the request, currently everything is handled and put together via "main()"
      *
-     * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/File/ReplaceFileController.php b/typo3/sysext/backend/Classes/Controller/File/ReplaceFileController.php
index 2e7dddff71fb..12ba4c2844c2 100644
--- a/typo3/sysext/backend/Classes/Controller/File/ReplaceFileController.php
+++ b/typo3/sysext/backend/Classes/Controller/File/ReplaceFileController.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Controller\File;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException;
@@ -192,15 +193,12 @@ class ReplaceFileController
      * Processes the request, currently everything is handled and put together via "main()"
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php b/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php
index 5b069f7261d1..785fee5fc2cf 100644
--- a/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php
+++ b/typo3/sysext/backend/Classes/Controller/FileSystemNavigationFrameController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Tree\View\ElementBrowserFolderTreeView;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -77,16 +78,13 @@ class FileSystemNavigationFrameController
 
     /**
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->initPage();
         $this->main();
-
-        $response->getBody()->write($this->content);
-        return $response;
+        return new HtmlResponse($this->content);
     }
 
     /**
@@ -226,17 +224,16 @@ class FileSystemNavigationFrameController
      * Called by an AJAX Route, see AjaxRequestHandler
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function ajaxExpandCollapse(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function ajaxExpandCollapse(ServerRequestInterface $request): ResponseInterface
     {
         $this->init();
         $tree = $this->foldertree->getBrowsableTree();
         if ($this->foldertree->getAjaxStatus() === false) {
-            return $response->withStatus(500);
+            return new HtmlResponse('', 500);
         }
-        return GeneralUtility::makeInstance(JsonResponse::class, [$tree]);
+        return new JsonResponse([$tree]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/FlashMessageController.php b/typo3/sysext/backend/Classes/Controller/FlashMessageController.php
index 7d85b8cf5190..9bb273672e61 100644
--- a/typo3/sysext/backend/Classes/Controller/FlashMessageController.php
+++ b/typo3/sysext/backend/Classes/Controller/FlashMessageController.php
@@ -16,7 +16,6 @@ namespace TYPO3\CMS\Backend\Controller;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -29,10 +28,9 @@ class FlashMessageController
     /**
      * Renders the FlashMessages from queue and returns them as JSON.
      *
-     * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function getQueuedFlashMessagesAction(ServerRequestInterface $request): ResponseInterface
+    public function getQueuedFlashMessagesAction(): ResponseInterface
     {
         $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
         $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
@@ -47,6 +45,6 @@ class FlashMessageController
             ];
         }
 
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($messages);
+        return (new JsonResponse())->setPayload($messages);
     }
 }
diff --git a/typo3/sysext/backend/Classes/Controller/FormFlexAjaxController.php b/typo3/sysext/backend/Classes/Controller/FormFlexAjaxController.php
index 9a0521e99935..47db685291f7 100644
--- a/typo3/sysext/backend/Classes/Controller/FormFlexAjaxController.php
+++ b/typo3/sysext/backend/Classes/Controller/FormFlexAjaxController.php
@@ -180,6 +180,6 @@ class FormFlexAjaxController extends AbstractFormEngineAjaxController
         $requireJsModule = $this->createExecutableStringRepresentationOfRegisteredRequireJsModules($newContainerResult);
         $jsonResult['scriptCall'] = array_merge($requireJsModule, $jsonResult['scriptCall']);
 
-        return GeneralUtility::makeInstance(JsonResponse::class, $jsonResult);
+        return new JsonResponse($jsonResult);
     }
 }
diff --git a/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php b/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php
index fec04f11dfd7..37f3e6ae04e4 100644
--- a/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php
+++ b/typo3/sysext/backend/Classes/Controller/FormInlineAjaxController.php
@@ -162,7 +162,7 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController
         // Fade out and fade in the new record in the browser view to catch the user's eye
         $jsonArray['scriptCall'][] = 'inline.fadeOutFadeIn(' . GeneralUtility::quoteJSvalue($objectId . '_div') . ');';
 
-        return GeneralUtility::makeInstance(JsonResponse::class, $jsonArray);
+        return new JsonResponse($jsonArray);
     }
 
     /**
@@ -243,7 +243,7 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController
             $jsonArray['scriptCall'][] = 'inline.collapseAllRecords(' . GeneralUtility::quoteJSvalue($objectId) . ',' . GeneralUtility::quoteJSvalue($objectPrefix) . ',\'' . (int)$child['uid'] . '\');';
         }
 
-        return GeneralUtility::makeInstance(JsonResponse::class, $jsonArray);
+        return new JsonResponse($jsonArray);
     }
 
     /**
@@ -401,7 +401,7 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController
                 . ', json.data);';
             }
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($jsonArray);
+        return new JsonResponse($jsonArray);
     }
 
     /**
@@ -450,7 +450,7 @@ class FormInlineAjaxController extends AbstractFormEngineAjaxController
                 $backendUser->writeUC();
             }
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload([]);
+        return (new JsonResponse())->setPayload([]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/FormSelectTreeAjaxController.php b/typo3/sysext/backend/Classes/Controller/FormSelectTreeAjaxController.php
index 8a6e44724b53..f33f6fb0a51d 100644
--- a/typo3/sysext/backend/Classes/Controller/FormSelectTreeAjaxController.php
+++ b/typo3/sysext/backend/Classes/Controller/FormSelectTreeAjaxController.php
@@ -179,6 +179,6 @@ class FormSelectTreeAjaxController
         } else {
             $treeData = $formData['processedTca']['columns'][$fieldName]['config']['items'];
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($treeData);
+        return (new JsonResponse())->setPayload($treeData);
     }
 }
diff --git a/typo3/sysext/backend/Classes/Controller/LinkBrowserController.php b/typo3/sysext/backend/Classes/Controller/LinkBrowserController.php
index a66951861ea8..572a803b46c2 100644
--- a/typo3/sysext/backend/Classes/Controller/LinkBrowserController.php
+++ b/typo3/sysext/backend/Classes/Controller/LinkBrowserController.php
@@ -93,7 +93,7 @@ class LinkBrowserController extends AbstractLinkBrowserController
         }
 
         $typoLink = GeneralUtility::makeInstance(TypoLinkCodecService::class)->encode($typoLinkParts);
-        return GeneralUtility::makeInstance(JsonResponse::class, ['typoLink' => $typoLink]);
+        return new JsonResponse(['typoLink' => $typoLink]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/LiveSearchController.php b/typo3/sysext/backend/Classes/Controller/LiveSearchController.php
index baa69f1bfda3..4623a4dc2ded 100644
--- a/typo3/sysext/backend/Classes/Controller/LiveSearchController.php
+++ b/typo3/sysext/backend/Classes/Controller/LiveSearchController.php
@@ -59,6 +59,6 @@ class LiveSearchController
                 $searchResults[] = $item;
             }
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($searchResults);
+        return (new JsonResponse())->setPayload($searchResults);
     }
 }
diff --git a/typo3/sysext/backend/Classes/Controller/LoginController.php b/typo3/sysext/backend/Classes/Controller/LoginController.php
index aa99e82ed938..f6ae7ae6efa8 100644
--- a/typo3/sysext/backend/Classes/Controller/LoginController.php
+++ b/typo3/sysext/backend/Classes/Controller/LoginController.php
@@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -139,14 +140,11 @@ class LoginController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response the current response
      * @return ResponseInterface the finished response with the content
      */
-    public function formAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function formAction(ServerRequestInterface $request): ResponseInterface
     {
-        $content = $this->main();
-        $response->getBody()->write($content);
-        return $response;
+        return new HtmlResponse($this->main());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/LoginFramesetController.php b/typo3/sysext/backend/Classes/Controller/LoginFramesetController.php
index cb1baf950125..5228574c8079 100644
--- a/typo3/sysext/backend/Classes/Controller/LoginFramesetController.php
+++ b/typo3/sysext/backend/Classes/Controller/LoginFramesetController.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
@@ -42,14 +43,12 @@ class LoginFramesetController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        $response->getBody()->write($this->content);
-        return $response;
+        return new HtmlResponse($this->content);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/LogoutController.php b/typo3/sysext/backend/Classes/Controller/LogoutController.php
index 0979dfcdbdea..b4fe92507f4b 100644
--- a/typo3/sysext/backend/Classes/Controller/LogoutController.php
+++ b/typo3/sysext/backend/Classes/Controller/LogoutController.php
@@ -16,7 +16,9 @@ namespace TYPO3\CMS\Backend\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
+use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
@@ -31,23 +33,19 @@ class LogoutController
      * This will be split up in an abstract controller once proper routing/dispatcher is in place.
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function logoutAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function logoutAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->logout();
 
         $redirectUrl = $request->getParsedBody()['redirect'] ?? $request->getQueryParams()['redirect'];
         $redirectUrl = GeneralUtility::sanitizeLocalUrl($redirectUrl);
         if (empty($redirectUrl)) {
-            /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
-            $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
+            $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
             $redirectUrl = (string)$uriBuilder->buildUriFromRoute('login', [], $uriBuilder::ABSOLUTE_URL);
         }
-        return $response
-            ->withStatus(303)
-            ->withHeader('Location', GeneralUtility::locationHeaderUrl($redirectUrl));
+        return new RedirectResponse(GeneralUtility::locationHeaderUrl($redirectUrl), 303);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/NewRecordController.php b/typo3/sysext/backend/Classes/Controller/NewRecordController.php
index 62a765c1ac86..a4c3900febed 100644
--- a/typo3/sysext/backend/Classes/Controller/NewRecordController.php
+++ b/typo3/sysext/backend/Classes/Controller/NewRecordController.php
@@ -24,6 +24,7 @@ use TYPO3\CMS\Backend\Tree\View\PagePositionMap;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
@@ -248,15 +249,12 @@ class NewRecordController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/OnlineMediaController.php b/typo3/sysext/backend/Classes/Controller/OnlineMediaController.php
index 23b5dc4093e1..a61cd120da69 100644
--- a/typo3/sysext/backend/Classes/Controller/OnlineMediaController.php
+++ b/typo3/sysext/backend/Classes/Controller/OnlineMediaController.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -34,10 +35,9 @@ class OnlineMediaController
     /**
      * AJAX endpoint for storing the URL as a sys_file record
      *
-     * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function createAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function createAction(ServerRequestInterface $request): ResponseInterface
     {
         $url = $request->getParsedBody()['url'];
         $targetFolderIdentifier = $request->getParsedBody()['targetFolder'];
@@ -51,9 +51,9 @@ class OnlineMediaController
             } else {
                 $data['error'] = $this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:online_media.error.invalid_url');
             }
-            return GeneralUtility::makeInstance(JsonResponse::class, $data);
+            return new JsonResponse($data);
         }
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
@@ -61,8 +61,9 @@ class OnlineMediaController
      *
      * @param ServerRequestInterface $request
      * @return ResponseInterface
+     * @throws \RuntimeException
      */
-    public function mainAction(ServerRequestInterface $request)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $files = $request->getParsedBody()['data'];
         $redirect = $request->getParsedBody()['redirect'];
diff --git a/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php b/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php
index 548acdc2bd2c..8650faaadd33 100644
--- a/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php
+++ b/typo3/sysext/backend/Classes/Controller/Page/LocalizationController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Configuration\TranslationConfigurationProvider;
 use TYPO3\CMS\Backend\Domain\Repository\Localization\LocalizationRepository;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
@@ -64,15 +65,13 @@ class LocalizationController
      * Get used languages in a colPos of a page
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function getUsedLanguagesInPageAndColumn(ServerRequestInterface $request, ResponseInterface $response)
+    public function getUsedLanguagesInPageAndColumn(ServerRequestInterface $request): ResponseInterface
     {
         $params = $request->getQueryParams();
         if (!isset($params['pageId'], $params['colPos'], $params['languageId'])) {
-            $response = $response->withStatus(400);
-            return $response;
+            return new HtmlResponse('', 400);
         }
 
         $pageId = (int)$params['pageId'];
@@ -111,22 +110,20 @@ class LocalizationController
             }
         }
 
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($availableLanguages);
+        return (new JsonResponse())->setPayload($availableLanguages);
     }
 
     /**
      * Get a prepared summary of records being translated
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function getRecordLocalizeSummary(ServerRequestInterface $request, ResponseInterface $response)
+    public function getRecordLocalizeSummary(ServerRequestInterface $request): ResponseInterface
     {
         $params = $request->getQueryParams();
         if (!isset($params['pageId'], $params['colPos'], $params['destLanguageId'], $params['languageId'])) {
-            $response = $response->withStatus(400);
-            return $response;
+            return new HtmlResponse('', 400);
         }
 
         $records = [];
@@ -150,26 +147,22 @@ class LocalizationController
             ];
         }
 
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($records);
+        return (new JsonResponse())->setPayload($records);
     }
 
     /**
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function localizeRecords(ServerRequestInterface $request, ResponseInterface $response)
+    public function localizeRecords(ServerRequestInterface $request): ResponseInterface
     {
         $params = $request->getQueryParams();
         if (!isset($params['pageId'], $params['srcLanguageId'], $params['destLanguageId'], $params['action'], $params['uidList'])) {
-            $response = $response->withStatus(400);
-            return $response;
+            return new HtmlResponse('', 400);
         }
 
         if ($params['action'] !== static::ACTION_COPY && $params['action'] !== static::ACTION_LOCALIZE) {
-            $response->getBody()->write('Invalid action "' . $params['action'] . '" called.');
-            $response = $response->withStatus(400);
-            return $response;
+            return new HtmlResponse('Invalid action "' . $params['action'] . '" called.', 400);
         }
 
         // Filter transmitted but invalid uids
@@ -183,7 +176,7 @@ class LocalizationController
 
         $this->process($params);
 
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload([]);
+        return (new JsonResponse())->setPayload([]);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Page/NewMultiplePagesController.php b/typo3/sysext/backend/Classes/Controller/Page/NewMultiplePagesController.php
index d25a21d52913..2fe38892c193 100644
--- a/typo3/sysext/backend/Classes/Controller/Page/NewMultiplePagesController.php
+++ b/typo3/sysext/backend/Classes/Controller/Page/NewMultiplePagesController.php
@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -57,10 +58,9 @@ class NewMultiplePagesController
      * Main function Handling input variables and rendering main view
      *
      * @param $request ServerRequestInterface
-     * @param $response ResponseInterface
      * @return ResponseInterface Response
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $backendUser = $this->getBackendUser();
         $pageUid = (int)$request->getQueryParams()['id'];
@@ -70,8 +70,7 @@ class NewMultiplePagesController
         if (!is_array($pageRecord)) {
             // User has no permission on parent page, should not happen, just render an empty page
             $this->moduleTemplate->setContent('');
-            $response->getBody()->write($this->moduleTemplate->renderContent());
-            return $response;
+            return new HtmlResponse($this->moduleTemplate->renderContent());
         }
 
         // Doc header handling
@@ -130,8 +129,7 @@ class NewMultiplePagesController
         }
 
         $this->moduleTemplate->setContent($view->render());
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Page/SortSubPagesController.php b/typo3/sysext/backend/Classes/Controller/Page/SortSubPagesController.php
index db051643819b..fac05ced3aa5 100644
--- a/typo3/sysext/backend/Classes/Controller/Page/SortSubPagesController.php
+++ b/typo3/sysext/backend/Classes/Controller/Page/SortSubPagesController.php
@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -56,10 +57,9 @@ class SortSubPagesController
      * Main function Handling input variables and rendering main view
      *
      * @param $request ServerRequestInterface
-     * @param $response ResponseInterface
      * @return ResponseInterface Response
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $backendUser = $this->getBackendUser();
         $parentPageUid = (int)$request->getQueryParams()['id'];
@@ -69,8 +69,7 @@ class SortSubPagesController
         if (!is_array($pageInformation)) {
             // User has no permission on parent page, should not happen, just render an empty page
             $this->moduleTemplate->setContent('');
-            $response->getBody()->write($this->moduleTemplate->renderContent());
-            return $response;
+            return new HtmlResponse($this->moduleTemplate->renderContent());
         }
 
         // Doc header handling
@@ -133,8 +132,7 @@ class SortSubPagesController
         }
 
         $this->moduleTemplate->setContent($view->render());
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Page/TreeController.php b/typo3/sysext/backend/Classes/Controller/Page/TreeController.php
index 5ededca0cb43..88478d3fc4af 100644
--- a/typo3/sysext/backend/Classes/Controller/Page/TreeController.php
+++ b/typo3/sysext/backend/Classes/Controller/Page/TreeController.php
@@ -122,7 +122,7 @@ class TreeController
             'temporaryMountPoint' => $this->getMountPointPath((int)($this->getBackendUser()->uc['pageTree_temporaryMountPoint'] ?? 0)),
         ];
 
-        return GeneralUtility::makeInstance(JsonResponse::class, $configuration);
+        return new JsonResponse($configuration);
     }
 
     /**
@@ -197,7 +197,7 @@ class TreeController
             $items = array_merge($items, $this->pagesToFlatArray($page, (int)$page['uid']));
         }
 
-        return GeneralUtility::makeInstance(JsonResponse::class, $items);
+        return new JsonResponse($items);
     }
 
     /**
@@ -222,7 +222,7 @@ class TreeController
         $response = [
             'mountPointPath' => $this->getMountPointPath($pid)
         ];
-        return GeneralUtility::makeInstance(JsonResponse::class, $response);
+        return new JsonResponse($response);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php
index 23549fdad8d1..ced13cd02f7a 100644
--- a/typo3/sysext/backend/Classes/Controller/PageLayoutController.php
+++ b/typo3/sysext/backend/Classes/Controller/PageLayoutController.php
@@ -28,6 +28,7 @@ use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Page\PageRenderer;
@@ -668,17 +669,15 @@ class PageLayoutController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $GLOBALS['SOBE'] = $this;
         $this->init();
         $this->clearCache();
         $this->main();
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/SimpleDataHandlerController.php b/typo3/sysext/backend/Classes/Controller/SimpleDataHandlerController.php
index d222d9ec564c..34268d9a2658 100644
--- a/typo3/sysext/backend/Classes/Controller/SimpleDataHandlerController.php
+++ b/typo3/sysext/backend/Classes/Controller/SimpleDataHandlerController.php
@@ -19,7 +19,9 @@ use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Clipboard\Clipboard;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
+use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Core\Messaging\AbstractMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -192,10 +194,9 @@ class SimpleDataHandlerController
      * As this controller goes only through the main() method, it just redirects to the given URL afterwards.
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->initClipboard();
         $this->main();
@@ -203,11 +204,9 @@ class SimpleDataHandlerController
         // Write errors to flash message queue
         $this->tce->printLogErrorMessages();
         if ($this->redirect) {
-            $response = $response
-                ->withHeader('Location', GeneralUtility::locationHeaderUrl($this->redirect))
-                ->withStatus(303);
+            return new RedirectResponse(GeneralUtility::locationHeaderUrl($this->redirect), 303);
         }
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
@@ -247,7 +246,7 @@ class SimpleDataHandlerController
                 }
             }
         }
-        return GeneralUtility::makeInstance(JsonResponse::class, $content);
+        return new JsonResponse($content);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/UserSettingsController.php b/typo3/sysext/backend/Classes/Controller/UserSettingsController.php
index ad104fb32ce1..3f603f2abbb3 100644
--- a/typo3/sysext/backend/Classes/Controller/UserSettingsController.php
+++ b/typo3/sysext/backend/Classes/Controller/UserSettingsController.php
@@ -41,7 +41,7 @@ class UserSettingsController
         $value = $request->getParsedBody()['value'] ?? $request->getQueryParams()['value'];
 
         $content = $this->process($action, $key, $value);
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($content);
+        return (new JsonResponse())->setPayload($content);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/AddController.php b/typo3/sysext/backend/Classes/Controller/Wizard/AddController.php
index 234e6fc8c2da..9409830391d4 100644
--- a/typo3/sysext/backend/Classes/Controller/Wizard/AddController.php
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/AddController.php
@@ -21,6 +21,7 @@ use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
@@ -155,13 +156,12 @@ class AddController extends AbstractWizardController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/EditController.php b/typo3/sysext/backend/Classes/Controller/Wizard/EditController.php
index 6b8884f547b4..553c84c58ae9 100644
--- a/typo3/sysext/backend/Classes/Controller/Wizard/EditController.php
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/EditController.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Controller\Wizard;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Core\Database\RelationHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
@@ -73,14 +74,12 @@ class EditController extends AbstractWizardController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $content = $this->main();
-        $response->getBody()->write($content);
-        return $response;
+        return new HtmlResponse($content);
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/ListController.php b/typo3/sysext/backend/Classes/Controller/Wizard/ListController.php
index d08fab80f470..344724cdc7b8 100644
--- a/typo3/sysext/backend/Classes/Controller/Wizard/ListController.php
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/ListController.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Controller\Wizard;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 
@@ -68,13 +69,12 @@ class ListController extends AbstractWizardController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php b/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
index 8ec88aba8e84..f1ab5fcbf935 100644
--- a/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/SuggestWizardController.php
@@ -161,7 +161,7 @@ class SuggestWizardController
         $maxItems = min(count($resultRows), $maxItems);
 
         array_splice($resultRows, $maxItems);
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload(array_values($resultRows));
+        return (new JsonResponse())->setPayload(array_values($resultRows));
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Controller/Wizard/TableController.php b/typo3/sysext/backend/Classes/Controller/Wizard/TableController.php
index 5b2296129086..9cd3f6140cc3 100644
--- a/typo3/sysext/backend/Classes/Controller/Wizard/TableController.php
+++ b/typo3/sysext/backend/Classes/Controller/Wizard/TableController.php
@@ -21,6 +21,7 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -145,14 +146,12 @@ class TableController extends AbstractWizardController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/backend/Classes/Form/Wizard/ImageManipulationWizard.php b/typo3/sysext/backend/Classes/Form/Wizard/ImageManipulationWizard.php
index 0b10301a7539..69ce4d190b80 100644
--- a/typo3/sysext/backend/Classes/Form/Wizard/ImageManipulationWizard.php
+++ b/typo3/sysext/backend/Classes/Form/Wizard/ImageManipulationWizard.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Backend\Form\Wizard;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -51,10 +52,9 @@ class ImageManipulationWizard
      * Returns the HTML for the wizard inside the modal
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface $response
      */
-    public function getWizardAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function getWizardAction(ServerRequestInterface $request): ResponseInterface
     {
         if ($this->isSignatureValid($request)) {
             $queryParams = json_decode($request->getQueryParams()['arguments'], true);
@@ -71,11 +71,9 @@ class ImageManipulationWizard
                 'cropVariants' => $queryParams['cropVariants']
             ];
             $content = $this->templateView->renderSection('Main', $viewData);
-            $response->getBody()->write($content);
-
-            return $response;
+            return new HtmlResponse($content);
         }
-        return $response->withStatus(403);
+        return new HtmlResponse('', 403);
     }
 
     /**
diff --git a/typo3/sysext/backend/Tests/Unit/Controller/FormInlineAjaxControllerTest.php b/typo3/sysext/backend/Tests/Unit/Controller/FormInlineAjaxControllerTest.php
index ead320561c5c..ebfcf8250ac0 100644
--- a/typo3/sysext/backend/Tests/Unit/Controller/FormInlineAjaxControllerTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Controller/FormInlineAjaxControllerTest.php
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Controller\FormInlineAjaxController;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
@@ -34,7 +33,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function createActionThrowsExceptionIfContextIsEmpty()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -45,7 +43,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751361);
-        (new FormInlineAjaxController())->createAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->createAction($requestProphecy->reveal());
     }
 
     /**
@@ -53,7 +51,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function createActionThrowsExceptionIfContextConfigSectionIsEmpty()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -64,7 +61,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751362);
-        (new FormInlineAjaxController())->createAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->createAction($requestProphecy->reveal());
     }
 
     /**
@@ -72,7 +69,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function createActionThrowsExceptionIfContextConfigSectionDoesNotValidate()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -90,7 +86,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751363);
-        (new FormInlineAjaxController())->createAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->createAction($requestProphecy->reveal());
     }
 
     /**
@@ -98,7 +94,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function detailsActionThrowsExceptionIfContextIsEmpty()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -109,7 +104,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751361);
-        (new FormInlineAjaxController())->detailsAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->detailsAction($requestProphecy->reveal());
     }
 
     /**
@@ -117,7 +112,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function detailsActionThrowsExceptionIfContextConfigSectionIsEmpty()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -128,7 +122,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751362);
-        (new FormInlineAjaxController())->detailsAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->detailsAction($requestProphecy->reveal());
     }
 
     /**
@@ -136,7 +130,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function detailsActionThrowsExceptionIfContextConfigSectionDoesNotValidate()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -154,7 +147,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751363);
-        (new FormInlineAjaxController())->detailsAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->detailsAction($requestProphecy->reveal());
     }
 
     /**
@@ -162,7 +155,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function synchronizeLocalizeActionThrowsExceptionIfContextIsEmpty()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -173,7 +165,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751361);
-        (new FormInlineAjaxController())->synchronizeLocalizeAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->synchronizeLocalizeAction($requestProphecy->reveal());
     }
 
     /**
@@ -181,7 +173,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function synchronizeLocalizeActionThrowsExceptionIfContextConfigSectionIsEmpty()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -192,7 +183,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751362);
-        (new FormInlineAjaxController())->synchronizeLocalizeAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->synchronizeLocalizeAction($requestProphecy->reveal());
     }
 
     /**
@@ -200,7 +191,6 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
      */
     public function synchronizeLocalizeActionThrowsExceptionIfContextConfigSectionDoesNotValidate()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getParsedBody()->shouldBeCalled()->willReturn(
             [
@@ -218,7 +208,7 @@ class FormInlineAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit\Uni
         );
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1489751363);
-        (new FormInlineAjaxController())->synchronizeLocalizeAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormInlineAjaxController())->synchronizeLocalizeAction($requestProphecy->reveal());
     }
 
     /**
diff --git a/typo3/sysext/backend/Tests/Unit/Controller/FormSelectTreeAjaxControllerTest.php b/typo3/sysext/backend/Tests/Unit/Controller/FormSelectTreeAjaxControllerTest.php
index 9e2ebaf14bb1..78cdae5814e8 100644
--- a/typo3/sysext/backend/Tests/Unit/Controller/FormSelectTreeAjaxControllerTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Controller/FormSelectTreeAjaxControllerTest.php
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Controller;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Controller\FormSelectTreeAjaxController;
 
@@ -29,10 +28,9 @@ class FormSelectTreeAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit
     public function fetchDataActionThrowsExceptionIfTcaOfTableDoesNotExist()
     {
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1479386729);
-        (new FormSelectTreeAjaxController())->fetchDataAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormSelectTreeAjaxController())->fetchDataAction($requestProphecy->reveal());
     }
 
     /**
@@ -40,7 +38,6 @@ class FormSelectTreeAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit
      */
     public function fetchDataActionThrowsExceptionIfTcaOfTableFieldDoesNotExist()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $requestProphecy = $this->prophesize(ServerRequestInterface::class);
         $requestProphecy->getQueryParams()->shouldBeCalled()->willReturn([
             'tableName' => 'aTable',
@@ -49,6 +46,6 @@ class FormSelectTreeAjaxControllerTest extends \TYPO3\TestingFramework\Core\Unit
         $GLOBALS['TCA']['aTable']['columns'] = [];
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1479386990);
-        (new FormSelectTreeAjaxController())->fetchDataAction($requestProphecy->reveal(), $responseProphecy->reveal());
+        (new FormSelectTreeAjaxController())->fetchDataAction($requestProphecy->reveal());
     }
 }
diff --git a/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php b/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php
index 2b724c62b38e..fdd5f78082ba 100644
--- a/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php
+++ b/typo3/sysext/backend/Tests/Unit/Controller/Wizard/SuggestWizardControllerTest.php
@@ -14,7 +14,6 @@ namespace TYPO3\CMS\Backend\Tests\Unit\Controller\Wizard;
  * The TYPO3 project - inspiring people to share!
  */
 
-use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Controller\Wizard\SuggestWizardController;
 use TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools;
@@ -35,7 +34,6 @@ class SuggestWizardControllerTest extends \TYPO3\TestingFramework\Core\Unit\Unit
      */
     public function getFlexFieldConfigurationThrowsExceptionIfSimpleFlexFieldIsNotFound()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $serverRequestProphecy = $this->prophesize(ServerRequestInterface::class);
         $serverRequestProphecy->getParsedBody()->willReturn([
             'value' => 'theSearchValue',
@@ -73,7 +71,7 @@ class SuggestWizardControllerTest extends \TYPO3\TestingFramework\Core\Unit\Unit
 
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1480609491);
-        (new SuggestWizardController())->searchAction($serverRequestProphecy->reveal(), $responseProphecy->reveal());
+        (new SuggestWizardController())->searchAction($serverRequestProphecy->reveal());
     }
 
     /**
@@ -81,7 +79,6 @@ class SuggestWizardControllerTest extends \TYPO3\TestingFramework\Core\Unit\Unit
      */
     public function getFlexFieldConfigurationThrowsExceptionIfSectionContainerFlexFieldIsNotFound()
     {
-        $responseProphecy = $this->prophesize(ResponseInterface::class);
         $serverRequestProphecy = $this->prophesize(ServerRequestInterface::class);
         $serverRequestProphecy->getParsedBody()->willReturn([
             'value' => 'theSearchValue',
@@ -119,7 +116,7 @@ class SuggestWizardControllerTest extends \TYPO3\TestingFramework\Core\Unit\Unit
 
         $this->expectException(\RuntimeException::class);
         $this->expectExceptionCode(1480611208);
-        (new SuggestWizardController())->searchAction($serverRequestProphecy->reveal(), $responseProphecy->reveal());
+        (new SuggestWizardController())->searchAction($serverRequestProphecy->reveal());
     }
 
     /**
diff --git a/typo3/sysext/beuser/Classes/Controller/PermissionAjaxController.php b/typo3/sysext/beuser/Classes/Controller/PermissionAjaxController.php
index 23c2f355a5d3..bc51e2e675c1 100644
--- a/typo3/sysext/beuser/Classes/Controller/PermissionAjaxController.php
+++ b/typo3/sysext/beuser/Classes/Controller/PermissionAjaxController.php
@@ -18,6 +18,7 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
@@ -70,10 +71,9 @@ class PermissionAjaxController
      * The main dispatcher function. Collect data and prepare HTML output.
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function dispatch(ServerRequestInterface $request, ResponseInterface $response)
+    public function dispatch(ServerRequestInterface $request): ResponseInterface
     {
         $extPath = ExtensionManagementUtility::extPath('beuser');
 
@@ -81,13 +81,12 @@ class PermissionAjaxController
         $view->setPartialRootPaths(['default' => ExtensionManagementUtility::extPath('beuser') . 'Resources/Private/Partials']);
         $view->assign('pageId', $this->conf['page']);
 
-        $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
+        $response = new HtmlResponse('');
 
         // Basic test for required value
         if ($this->conf['page'] <= 0) {
             $response->getBody()->write('This script cannot be called directly');
-            $response = $response->withStatus(500);
-            return $response;
+            return $response->withStatus(500);
         }
 
         $content = '';
diff --git a/typo3/sysext/core/Classes/Controller/FileDumpController.php b/typo3/sysext/core/Classes/Controller/FileDumpController.php
index 5f1cd07308cc..f80f97c480f3 100644
--- a/typo3/sysext/core/Classes/Controller/FileDumpController.php
+++ b/typo3/sysext/core/Classes/Controller/FileDumpController.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Resource\Hook\FileDumpEIDHookInterface;
 use TYPO3\CMS\Core\Resource\ProcessedFileRepository;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
@@ -31,7 +32,6 @@ class FileDumpController
      * Main method to dump a file
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface|null
      *
      * @throws \InvalidArgumentException
@@ -39,7 +39,7 @@ class FileDumpController
      * @throws \TYPO3\CMS\Core\Resource\Exception\FileDoesNotExistException
      * @throws \UnexpectedValueException
      */
-    public function dumpAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function dumpAction(ServerRequestInterface $request)
     {
         $parameters = ['eID' => 'dumpFile'];
         $t = $this->getGetOrPost($request, 't');
@@ -88,7 +88,7 @@ class FileDumpController
             // @todo Refactor FAL to not echo directly, but to implement a stream for output here and use response
             return null;
         }
-        return $response->withStatus(403);
+        return new HtmlResponse('', 403);
     }
 
     /**
diff --git a/typo3/sysext/core/Classes/Imaging/IconFactory.php b/typo3/sysext/core/Classes/Imaging/IconFactory.php
index 8a9794d8e782..f2fe258a4010 100644
--- a/typo3/sysext/core/Classes/Imaging/IconFactory.php
+++ b/typo3/sysext/core/Classes/Imaging/IconFactory.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Core\Imaging;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Resource\File;
 use TYPO3\CMS\Core\Resource\FolderInterface;
 use TYPO3\CMS\Core\Resource\InaccessibleFolder;
@@ -71,11 +72,10 @@ class IconFactory
 
     /**
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
-     * @return string
+     * @return ResponseInterface
      * @internal
      */
-    public function processAjaxRequest(ServerRequestInterface $request, ResponseInterface $response)
+    public function processAjaxRequest(ServerRequestInterface $request): ResponseInterface
     {
         $parsedBody = $request->getParsedBody();
         $queryParams = $request->getQueryParams();
@@ -89,11 +89,7 @@ class IconFactory
             $overlayIdentifier = null;
         }
         $iconState = IconState::cast($iconState);
-        $response->getBody()->write(
-            $this->getIcon($identifier, $size, $overlayIdentifier, $iconState)->render($alternativeMarkupIdentifier)
-        );
-        $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
-        return $response;
+        return new HtmlResponse($this->getIcon($identifier, $size, $overlayIdentifier, $iconState)->render($alternativeMarkupIdentifier));
     }
 
     /**
diff --git a/typo3/sysext/documentation/Classes/Controller/DocumentController.php b/typo3/sysext/documentation/Classes/Controller/DocumentController.php
index adb02c926f90..6ca16b9fa70c 100644
--- a/typo3/sysext/documentation/Classes/Controller/DocumentController.php
+++ b/typo3/sysext/documentation/Classes/Controller/DocumentController.php
@@ -181,7 +181,7 @@ class DocumentController extends ActionController
      * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function deleteAction(ServerRequestInterface $request)
+    public function deleteAction(ServerRequestInterface $request): ResponseInterface
     {
         $basePath = 'typo3conf/Documentation/';
         $packageKey = $request->getParsedBody();
@@ -189,8 +189,7 @@ class DocumentController extends ActionController
         if (!$isDirDeleted) {
             $this->addFlashMessage(LocalizationUtility::translate('deleteFailed', 'Documentation'), '', FlashMessage::ERROR);
         }
-
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload([$isDirDeleted]);
+        return new JsonResponse([$isDirDeleted]);
     }
 
     /**
diff --git a/typo3/sysext/frontend/Classes/Controller/ShowImageController.php b/typo3/sysext/frontend/Classes/Controller/ShowImageController.php
index d1f8a63f0901..370988af5025 100644
--- a/typo3/sysext/frontend/Classes/Controller/ShowImageController.php
+++ b/typo3/sysext/frontend/Classes/Controller/ShowImageController.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Frontend\Controller;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Core\Exception;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Resource\ProcessedFile;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -190,23 +191,21 @@ EOF;
      * Fetches the content and builds a content file out of it
      *
      * @param ServerRequestInterface $request the current request object
-     * @param ResponseInterface $response the available response
      * @return ResponseInterface the modified response
      */
-    public function processRequest(ServerRequestInterface $request, ResponseInterface $response)
+    public function processRequest(ServerRequestInterface $request): ResponseInterface
     {
         $this->request = $request;
 
         try {
             $this->initialize();
             $this->main();
-            $response->getBody()->write($this->content);
-            return $response;
+            return new HtmlResponse($this->content);
         } catch (\InvalidArgumentException $e) {
             // add a 410 "gone" if invalid parameters given
-            return $response->withStatus(410);
+            return new HtmlResponse('', 410);
         } catch (Exception $e) {
-            return $response->withStatus(404);
+            return new HtmlResponse('', 404);
         }
     }
 }
diff --git a/typo3/sysext/impexp/Classes/Controller/ImportExportController.php b/typo3/sysext/impexp/Classes/Controller/ImportExportController.php
index 2a7b98760334..de8c2d27602f 100644
--- a/typo3/sysext/impexp/Classes/Controller/ImportExportController.php
+++ b/typo3/sysext/impexp/Classes/Controller/ImportExportController.php
@@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\QueryHelper;
 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -292,18 +293,15 @@ class ImportExportController extends BaseScriptClass
      * external_ref[tables][]=table/_ALL
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $GLOBALS['SOBE'] = $this;
         $this->init();
         $this->main();
         $this->moduleTemplate->setContent($this->standaloneView->render());
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/info/Classes/Controller/InfoModuleController.php b/typo3/sysext/info/Classes/Controller/InfoModuleController.php
index 77a740bafa5d..9a7b480b6af5 100644
--- a/typo3/sysext/info/Classes/Controller/InfoModuleController.php
+++ b/typo3/sysext/info/Classes/Controller/InfoModuleController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Module\BaseScriptClass;
 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
@@ -132,10 +133,9 @@ class InfoModuleController extends BaseScriptClass
      * Then checks for module functions that have hooked in, and renders menu etc.
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $GLOBALS['SOBE'] = $this;
         $this->init();
@@ -148,8 +148,7 @@ class InfoModuleController extends BaseScriptClass
         $this->main();
 
         $this->moduleTemplate->setContent($this->content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/install/Classes/Controller/BackendModuleController.php b/typo3/sysext/install/Classes/Controller/BackendModuleController.php
index 13e7c0f64e6a..64fdd86716a5 100644
--- a/typo3/sysext/install/Classes/Controller/BackendModuleController.php
+++ b/typo3/sysext/install/Classes/Controller/BackendModuleController.php
@@ -16,7 +16,6 @@ namespace TYPO3\CMS\Install\Controller;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Install\Service\SessionService;
 
@@ -34,11 +33,9 @@ class BackendModuleController
     /**
      * Initialize session and redirect to "maintenance"
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function maintenanceAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function maintenanceAction(): ResponseInterface
     {
         return $this->setAuthorizedAndRedirect('maintenance');
     }
@@ -46,11 +43,9 @@ class BackendModuleController
     /**
      * Initialize session and redirect to "settings"
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function settingsAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function settingsAction(): ResponseInterface
     {
         return $this->setAuthorizedAndRedirect('settings');
     }
@@ -58,11 +53,9 @@ class BackendModuleController
     /**
      * Initialize session and redirect to "upgrade"
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function upgradeAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function upgradeAction(): ResponseInterface
     {
         return $this->setAuthorizedAndRedirect('upgrade');
     }
@@ -70,11 +63,9 @@ class BackendModuleController
     /**
      * Initialize session and redirect to "environment"
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function environmentAction(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface
+    public function environmentAction(): ResponseInterface
     {
         return $this->setAuthorizedAndRedirect('environment');
     }
diff --git a/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php b/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php
index 90295e8172d9..6518b8d49600 100644
--- a/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php
+++ b/typo3/sysext/lowlevel/Classes/Controller/ConfigurationController.php
@@ -22,6 +22,7 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Cache\Backend\NullBackend;
 use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\MiddlewareStackResolver;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Package\PackageManager;
@@ -147,11 +148,10 @@ class ConfigurationController
      * and renders it.
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      * @throws \RuntimeException
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $backendUser = $this->getBackendUser();
         $languageService = $this->getLanguageService();
@@ -304,8 +304,7 @@ class ConfigurationController
         }
         $moduleTemplate->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
 
-        $response->getBody()->write($moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php b/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php
index 33b778fb5411..59b1eef5dbb9 100644
--- a/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php
+++ b/typo3/sysext/lowlevel/Classes/Controller/DatabaseIntegrityController.php
@@ -21,6 +21,7 @@ use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\QueryView;
 use TYPO3\CMS\Core\Database\ReferenceIndex;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Integrity\DatabaseIntegrityCheck;
@@ -103,10 +104,9 @@ class DatabaseIntegrityController
      * Simply calls main() and init() and outputs the content
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->getLanguageService()->includeLLFile('EXT:lowlevel/Resources/Private/Language/locallang.xlf');
         $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
@@ -163,8 +163,7 @@ class DatabaseIntegrityController
         $this->getModuleMenu();
 
         $this->moduleTemplate->setContent($content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php b/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
index 6fadd03a7ede..55257aa666fc 100644
--- a/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
+++ b/typo3/sysext/opendocs/Classes/Backend/ToolbarItems/OpendocsToolbarItem.php
@@ -19,6 +19,7 @@ use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Toolbar\ToolbarItemInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Fluid\View\StandaloneView;
 
@@ -196,10 +197,9 @@ class OpendocsToolbarItem implements ToolbarItemInterface
      * Closes a document in the session and
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function closeDocument(ServerRequestInterface $request, ResponseInterface $response)
+    public function closeDocument(ServerRequestInterface $request): ResponseInterface
     {
         $md5sum = $request->getParsedBody()['md5sum'] ?? $request->getQueryParams()['md5sum'];
         if ($md5sum && isset($this->openDocs[$md5sum])) {
@@ -216,20 +216,17 @@ class OpendocsToolbarItem implements ToolbarItemInterface
             $backendUser->pushModuleData('FormEngine', [$this->openDocs, $docDat]);
             $backendUser->pushModuleData('opendocs::recent', $this->recentDocs);
         }
-        return $this->renderMenu($request, $response);
+        return $this->renderMenu();
     }
 
     /**
      * Renders the menu so that it can be returned as response to an AJAX call
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function renderMenu(ServerRequestInterface $request, ResponseInterface $response)
+    public function renderMenu(): ResponseInterface
     {
-        $response->getBody()->write($this->getDropDown());
-        return $response->withHeader('Content-Type', 'text/html; charset=utf-8');
+        return new HtmlResponse($this->getDropDown());
     }
 
     /**
diff --git a/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php b/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php
index 5caa794ea302..57cf96206b81 100644
--- a/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php
+++ b/typo3/sysext/recordlist/Classes/Controller/AbstractLinkBrowserController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Service\DependencyOrderingService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -147,10 +148,9 @@ abstract class AbstractLinkBrowserController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response the prepared response object
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->determineScriptUrl($request);
         $this->initVariables($request);
@@ -186,8 +186,7 @@ abstract class AbstractLinkBrowserController
         $content .= $browserContent;
         $content .= $this->doc->endPage();
 
-        $response->getBody()->write($this->doc->insertStylesAndJS($content));
-        return $response;
+        return new HtmlResponse($this->doc->insertStylesAndJS($content));
     }
 
     /**
diff --git a/typo3/sysext/recordlist/Classes/Controller/ElementBrowserController.php b/typo3/sysext/recordlist/Classes/Controller/ElementBrowserController.php
index b0c563c7de55..9f02502f2d3b 100644
--- a/typo3/sysext/recordlist/Classes/Controller/ElementBrowserController.php
+++ b/typo3/sysext/recordlist/Classes/Controller/ElementBrowserController.php
@@ -16,8 +16,11 @@ namespace TYPO3\CMS\Recordlist\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Routing\UriBuilder;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Http\HtmlResponse;
+use TYPO3\CMS\Core\Http\RedirectResponse;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Recordlist\Browser\ElementBrowserInterface;
@@ -76,20 +79,16 @@ class ElementBrowserController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response the prepared response object
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         // Fallback for old calls, which use mode "wizard" or "rte" for link selection
         if ($this->mode === 'wizard' || $this->mode === 'rte') {
-            /** @var \TYPO3\CMS\Backend\Routing\UriBuilder $uriBuilder */
-            $uriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
-            return $response->withStatus(303)->withHeader('Location', (string)$uriBuilder->buildUriFromRoute('wizard_link', $_GET));
+            $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
+            return new RedirectResponse((string)$uriBuilder->buildUriFromRoute('wizard_link', $_GET), 303);
         }
-
-        $response->getBody()->write($this->main());
-        return $response;
+        return new HtmlResponse($this->main());
     }
 
     /**
diff --git a/typo3/sysext/recordlist/Classes/Controller/ElementBrowserFramesetController.php b/typo3/sysext/recordlist/Classes/Controller/ElementBrowserFramesetController.php
index bc11b7b024f5..fe6c0f65464b 100644
--- a/typo3/sysext/recordlist/Classes/Controller/ElementBrowserFramesetController.php
+++ b/typo3/sysext/recordlist/Classes/Controller/ElementBrowserFramesetController.php
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Recordlist\Controller;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Template\DocumentTemplate;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -51,15 +52,12 @@ class ElementBrowserFramesetController
      * As this controller goes only through the main() method, it is rather simple for now
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response the prepared response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->main();
-
-        $response->getBody()->write($this->content);
-        return $response;
+        return new HtmlResponse($this->content);
     }
 
     /**
diff --git a/typo3/sysext/recordlist/Classes/RecordList.php b/typo3/sysext/recordlist/Classes/RecordList.php
index 2dcc33d56fb1..a15533e40050 100644
--- a/typo3/sysext/recordlist/Classes/RecordList.php
+++ b/typo3/sysext/recordlist/Classes/RecordList.php
@@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\HiddenRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -586,10 +587,9 @@ class RecordList
      * Simply calls main() and init() and outputs the content
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         BackendUtility::lockRecords();
         $GLOBALS['SOBE'] = $this;
@@ -597,8 +597,7 @@ class RecordList
         $this->clearCache();
         $this->main();
         $this->moduleTemplate->setContent($this->content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/recycler/Classes/Controller/RecyclerAjaxController.php b/typo3/sysext/recycler/Classes/Controller/RecyclerAjaxController.php
index e7237d4755ad..7a2759c1593c 100644
--- a/typo3/sysext/recycler/Classes/Controller/RecyclerAjaxController.php
+++ b/typo3/sysext/recycler/Classes/Controller/RecyclerAjaxController.php
@@ -64,7 +64,7 @@ class RecyclerAjaxController
      * @param ServerRequestInterface $request
      * @return ResponseInterface
      */
-    public function dispatch(ServerRequestInterface $request)
+    public function dispatch(ServerRequestInterface $request): ResponseInterface
     {
         $extPath = ExtensionManagementUtility::extPath('recycler');
         /* @var $view StandaloneView */
@@ -150,7 +150,7 @@ class RecyclerAjaxController
                 ];
                 break;
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($content);
+        return (new JsonResponse())->setPayload($content);
     }
 
     /**
diff --git a/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php b/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php
index 30659bc5ff0e..2fa83acac94b 100644
--- a/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php
+++ b/typo3/sysext/rsaauth/Classes/Controller/RsaPublicKeyGenerationController.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Rsaauth\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Rsaauth\Backend\BackendFactory;
 use TYPO3\CMS\Rsaauth\Storage\StorageFactory;
 
@@ -26,16 +27,15 @@ class RsaPublicKeyGenerationController
 {
     /**
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function processRequest(ServerRequestInterface $request, ResponseInterface $response)
+    public function processRequest(ServerRequestInterface $request): ResponseInterface
     {
         /** @var \TYPO3\CMS\Rsaauth\Backend\AbstractBackend $backend */
         $backend = BackendFactory::getBackend();
         if ($backend === null) {
             // add a HTTP 500 error code, if an error occurred
-            return $response->withStatus(500);
+            return new HtmlResponse('', 500);
         }
 
         $keyPair = $backend->createNewKeyPair();
@@ -43,7 +43,6 @@ class RsaPublicKeyGenerationController
         $storage->put($keyPair->getPrivateKey());
         session_commit();
         $content = $keyPair->getPublicKeyModulus() . ':' . sprintf('%x', $keyPair->getExponent()) . ':';
-        $response->getBody()->write($content);
-        return $response;
+        return new HtmlResponse($content);
     }
 }
diff --git a/typo3/sysext/rsaauth/Classes/RsaEncryptionEncoder.php b/typo3/sysext/rsaauth/Classes/RsaEncryptionEncoder.php
index fd31ea03d552..5bb6dda07404 100644
--- a/typo3/sysext/rsaauth/Classes/RsaEncryptionEncoder.php
+++ b/typo3/sysext/rsaauth/Classes/RsaEncryptionEncoder.php
@@ -15,7 +15,7 @@ namespace TYPO3\CMS\Rsaauth;
  */
 
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Page\PageRenderer;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
@@ -106,24 +106,20 @@ class RsaEncryptionEncoder implements SingletonInterface
     /**
      * Ajax handler to return a RSA public key.
      *
-     * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function getRsaPublicKeyAjaxHandler(ServerRequestInterface $request, ResponseInterface $response)
+    public function getRsaPublicKeyAjaxHandler(): ResponseInterface
     {
         $keyPair = $this->getRsaPublicKey();
         if ($keyPair !== null) {
-            $response->getBody()->write(implode('', [
-                'publicKeyModulus' => $keyPair->getPublicKeyModulus(),
-                'spacer' => ':',
-                'exponent' => sprintf('%x', $keyPair->getExponent())
-            ]));
-            $response = $response->withHeader('Content-Type', 'text/html; charset=utf-8');
-        } else {
-            $response->getBody()->write('No OpenSSL backend could be obtained for rsaauth.');
-            $response = $response->withStatus(500);
+            return new HtmlResponse(
+                implode('', [
+                    'publicKeyModulus' => $keyPair->getPublicKeyModulus(),
+                    'spacer' => ':',
+                    'exponent' => sprintf('%x', $keyPair->getExponent())
+                ])
+            );
         }
-        return $response;
+        return new HtmlResponse('No OpenSSL backend could be obtained for rsaauth.', 500);
     }
 }
diff --git a/typo3/sysext/scheduler/Classes/Controller/SchedulerModuleController.php b/typo3/sysext/scheduler/Classes/Controller/SchedulerModuleController.php
index cf7663911dfb..c602b12ad045 100644
--- a/typo3/sysext/scheduler/Classes/Controller/SchedulerModuleController.php
+++ b/typo3/sysext/scheduler/Classes/Controller/SchedulerModuleController.php
@@ -20,6 +20,7 @@ use TYPO3\CMS\Backend\Template\Components\ButtonBar;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Localization\LanguageService;
@@ -146,10 +147,9 @@ class SchedulerModuleController
      * Simply calls main() and init() and outputs the content
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $this->CMD = GeneralUtility::_GP('CMD');
         $this->MOD_MENU = [
@@ -179,8 +179,7 @@ class SchedulerModuleController
         $this->getModuleMenu();
 
         $this->moduleTemplate->setContent($content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/setup/Classes/Controller/SetupModuleController.php b/typo3/sysext/setup/Classes/Controller/SetupModuleController.php
index 8d70c150e0ce..8a2155641db4 100644
--- a/typo3/sysext/setup/Classes/Controller/SetupModuleController.php
+++ b/typo3/sysext/setup/Classes/Controller/SetupModuleController.php
@@ -24,6 +24,7 @@ use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
@@ -426,19 +427,16 @@ class SetupModuleController
      * Simply calls main() and init() and writes the content to the response
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $GLOBALS['SOBE'] = $this;
         $this->simulateUser();
         $this->init();
         $this->storeIncomingData();
         $this->main();
-
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/t3editor/Classes/CodeCompletion.php b/typo3/sysext/t3editor/Classes/CodeCompletion.php
index d234e82d00bd..5770cb21df24 100644
--- a/typo3/sysext/t3editor/Classes/CodeCompletion.php
+++ b/typo3/sysext/t3editor/Classes/CodeCompletion.php
@@ -15,9 +15,8 @@ namespace TYPO3\CMS\T3editor;
  */
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Http\JsonResponse;
-use TYPO3\CMS\Core\Http\Response;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Code completion for t3editor
@@ -42,10 +41,9 @@ class CodeCompletion
      * Called by AjaxRequestHandler
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function processAjaxRequest(ServerRequestInterface $request, ResponseInterface $response)
+    public function processAjaxRequest(ServerRequestInterface $request): ResponseInterface
     {
         $pageId = (int)($request->getParsedBody()['pageId'] ?? $request->getQueryParams()['pageId']);
         return $this->loadTemplates($pageId);
@@ -60,22 +58,15 @@ class CodeCompletion
      */
     protected function loadTemplates($pageId): ResponseInterface
     {
-        $response = GeneralUtility::makeInstance(Response::class);
-
         // Check whether access is granted (only admin have access to sys_template records):
         if ($GLOBALS['BE_USER']->isAdmin()) {
             // Check whether there is a pageId given:
             if ($pageId) {
-                $response = GeneralUtility::makeInstance(JsonResponse::class)->setPayload($this->getMergedTemplates($pageId));
-            } else {
-                $response->getBody()->write($GLOBALS['LANG']->getLL('pageIDInteger'));
-                $response = $response->withStatus(500);
+                return (new JsonResponse())->setPayload($this->getMergedTemplates($pageId));
             }
-        } else {
-            $response->getBody()->write($GLOBALS['LANG']->getLL('noPermission'));
-            $response = $response->withStatus(500);
+            return new HtmlResponse($GLOBALS['LANG']->getLL('pageIDInteger'), 500);
         }
-        return $response;
+        return new HtmlResponse($GLOBALS['LANG']->getLL('noPermission'), 500);
     }
 
     /**
@@ -83,10 +74,9 @@ class CodeCompletion
      *
      * @todo oliver@typo3.org: Refactor this method and comment what's going on there
      * @param int $pageId
-     * @param int $templateId
      * @return array Setup part of merged template records
      */
-    protected function getMergedTemplates($pageId, $templateId = 0)
+    protected function getMergedTemplates($pageId)
     {
         /** @var $tsParser \TYPO3\CMS\Core\TypoScript\ExtendedTemplateService */
         $tsParser = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\TypoScript\ExtendedTemplateService::class);
diff --git a/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php b/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php
index 7a58c7375b0f..ceec7d6df337 100644
--- a/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php
+++ b/typo3/sysext/t3editor/Classes/TypoScriptReferenceLoader.php
@@ -47,7 +47,7 @@ class TypoScriptReferenceLoader
     {
         // Load the TSref XML information:
         $this->loadFile(GeneralUtility::getFileAbsFileName('EXT:t3editor/Resources/Private/tsref.xml'));
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($this->getTypes());
+        return (new JsonResponse())->setPayload($this->getTypes());
     }
 
     /**
diff --git a/typo3/sysext/taskcenter/Classes/Controller/TaskModuleController.php b/typo3/sysext/taskcenter/Classes/Controller/TaskModuleController.php
index d3d65f9a6f7b..648f7871deae 100644
--- a/typo3/sysext/taskcenter/Classes/Controller/TaskModuleController.php
+++ b/typo3/sysext/taskcenter/Classes/Controller/TaskModuleController.php
@@ -19,6 +19,7 @@ use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Module\BaseScriptClass;
 use TYPO3\CMS\Backend\Template\ModuleTemplate;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\PathUtility;
@@ -120,18 +121,15 @@ class TaskModuleController extends BaseScriptClass
      * Simply calls main() and writes the content to the response
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $GLOBALS['SOBE'] = $this;
         $this->main();
 
         $this->moduleTemplate->setContent($this->content);
-
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/taskcenter/Classes/TaskStatus.php b/typo3/sysext/taskcenter/Classes/TaskStatus.php
index 59322eb38971..20aa6878f909 100644
--- a/typo3/sysext/taskcenter/Classes/TaskStatus.php
+++ b/typo3/sysext/taskcenter/Classes/TaskStatus.php
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Taskcenter;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 
 /**
  * Status of tasks
@@ -26,10 +27,9 @@ class TaskStatus
      * Saves the section toggle state of tasks in the backend user's uc
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function saveCollapseState(ServerRequestInterface $request, ResponseInterface $response)
+    public function saveCollapseState(ServerRequestInterface $request): ResponseInterface
     {
         // Remove 'el_' in the beginning which is needed for the saveSortingState()
         $item = $request->getParsedBody()['item'] ?? $request->getQueryParams()['item'];
@@ -39,17 +39,16 @@ class TaskStatus
         $this->getBackendUserAuthentication()->uc['taskcenter']['states'][$item] = $state;
         $this->getBackendUserAuthentication()->writeUC();
 
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
      * Saves the sorting order of tasks in the backend user's uc
      *
      * @param ServerRequestInterface $request
-     * @param ResponseInterface $response
      * @return ResponseInterface
      */
-    public function saveSortingState(ServerRequestInterface $request, ResponseInterface $response)
+    public function saveSortingState(ServerRequestInterface $request): ResponseInterface
     {
         $sort = [];
         $data = $request->getParsedBody()['data'] ?? $request->getQueryParams()['data'];
@@ -61,7 +60,7 @@ class TaskStatus
         $this->getBackendUserAuthentication()->uc['taskcenter']['sorting'] = serialize($sort);
         $this->getBackendUserAuthentication()->writeUC();
 
-        return $response;
+        return new HtmlResponse('');
     }
 
     /**
diff --git a/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php b/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
index 16781efa1d09..3795a33285ff 100644
--- a/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
+++ b/typo3/sysext/tstemplate/Classes/Controller/TypoScriptTemplateModuleController.php
@@ -24,6 +24,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Database\Query\Restriction\BackendWorkspaceRestriction;
 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
 use TYPO3\CMS\Core\DataHandling\DataHandler;
+use TYPO3\CMS\Core\Http\HtmlResponse;
 use TYPO3\CMS\Core\Imaging\Icon;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\TypoScript\ExtendedTemplateService;
@@ -275,10 +276,9 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
      * Then checks for module functions that have hooked in, and renders menu etc.
      *
      * @param ServerRequestInterface $request the current request
-     * @param ResponseInterface $response
      * @return ResponseInterface the response with the content
      */
-    public function mainAction(ServerRequestInterface $request, ResponseInterface $response)
+    public function mainAction(ServerRequestInterface $request): ResponseInterface
     {
         $GLOBALS['SOBE'] = $this;
         $this->init();
@@ -290,8 +290,7 @@ class TypoScriptTemplateModuleController extends BaseScriptClass
         $this->main();
 
         $this->moduleTemplate->setContent($this->content);
-        $response->getBody()->write($this->moduleTemplate->renderContent());
-        return $response;
+        return new HtmlResponse($this->moduleTemplate->renderContent());
     }
 
     /**
diff --git a/typo3/sysext/workspaces/Classes/Controller/AjaxController.php b/typo3/sysext/workspaces/Classes/Controller/AjaxController.php
index 4d87a5e29019..014ea515572f 100644
--- a/typo3/sysext/workspaces/Classes/Controller/AjaxController.php
+++ b/typo3/sysext/workspaces/Classes/Controller/AjaxController.php
@@ -18,7 +18,6 @@ use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
 use TYPO3\CMS\Core\Http\JsonResponse;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Implements the AJAX functionality for the various asynchronous calls
@@ -69,7 +68,7 @@ class AjaxController
             'workspaceId' => $workspaceId,
             'pageId'      => ($finalPageUid && $originalPageId == $finalPageUid) ? null : $finalPageUid
         ];
-        return GeneralUtility::makeInstance(JsonResponse::class, $ajaxResponse);
+        return new JsonResponse($ajaxResponse);
     }
 
     /**
diff --git a/typo3/sysext/workspaces/Classes/Controller/AjaxDispatcher.php b/typo3/sysext/workspaces/Classes/Controller/AjaxDispatcher.php
index 713e5ae1583d..c07e8750b19d 100644
--- a/typo3/sysext/workspaces/Classes/Controller/AjaxDispatcher.php
+++ b/typo3/sysext/workspaces/Classes/Controller/AjaxDispatcher.php
@@ -54,7 +54,7 @@ class AjaxDispatcher
             $instance = GeneralUtility::makeInstance($className);
             $results[] = $this->buildResultFromResponse(call_user_func_array([$instance, $method], $parameters), $call);
         }
-        return GeneralUtility::makeInstance(JsonResponse::class)->setPayload($results);
+        return (new JsonResponse())->setPayload($results);
     }
 
     /**
-- 
GitLab