[TASK] Deprecate Extbase's WebRequest and WebResponse 17/62317/5
authorAlexander Schnitzler <git@alexanderschnitzler.de>
Wed, 13 Nov 2019 11:57:09 +0000 (12:57 +0100)
committerDaniel Goerz <daniel.goerz@posteo.de>
Fri, 6 Dec 2019 20:32:30 +0000 (21:32 +0100)
In order to simplify the request/response handling in
Extbase and to prepare the introduction of PSR-7 compatible
request and response objects, the web versions of Extbase's
request and response have been deprecated. All relevant
logic has been moved into the base classes to stay api
compatible and not introduce a breaking change.

Along with the simplification of the request and response
objects, quite a lot of instance checks have been removed
to ease the transition to having a public api that is
defined by interfaces and not concrete implementations.

Releases: master
Resolves: #89673
Change-Id: Ie920ae7d38e6de3167ff57f93fa6e98af2936d9f
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/62317
Tested-by: TYPO3com <noreply@typo3.com>
Tested-by: Susanne Moog <look@susi.dev>
Tested-by: Daniel Goerz <daniel.goerz@posteo.de>
Reviewed-by: Jörg Bösche <typo3@joergboesche.de>
Reviewed-by: Susanne Moog <look@susi.dev>
Reviewed-by: Daniel Goerz <daniel.goerz@posteo.de>
13 files changed:
typo3/sysext/core/Documentation/Changelog/master/Deprecation-89673-DeprecateExtbasesWebRequestAndWebResponse.rst [new file with mode: 0644]
typo3/sysext/extbase/Classes/Core/Bootstrap.php
typo3/sysext/extbase/Classes/Mvc/Controller/ActionController.php
typo3/sysext/extbase/Classes/Mvc/Request.php
typo3/sysext/extbase/Classes/Mvc/Response.php
typo3/sysext/extbase/Classes/Mvc/View/JsonView.php
typo3/sysext/extbase/Classes/Mvc/Web/Request.php
typo3/sysext/extbase/Classes/Mvc/Web/Response.php
typo3/sysext/extbase/Classes/Mvc/Web/Routing/UriBuilder.php
typo3/sysext/fluid/Classes/Core/Widget/WidgetRequest.php
typo3/sysext/fluid/Classes/View/StandaloneView.php
typo3/sysext/form/Classes/Domain/Finishers/RedirectFinisher.php
typo3/sysext/indexed_search/Classes/Controller/AdministrationController.php

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89673-DeprecateExtbasesWebRequestAndWebResponse.rst b/typo3/sysext/core/Documentation/Changelog/master/Deprecation-89673-DeprecateExtbasesWebRequestAndWebResponse.rst
new file mode 100644 (file)
index 0000000..6edaa94
--- /dev/null
@@ -0,0 +1,45 @@
+.. include:: ../../Includes.txt
+
+====================================================================
+Deprecation: #89673 - Deprecate Extbase's WebRequest and WebResponse
+====================================================================
+
+See :issue:`89673`
+
+Description
+===========
+
+Both classes, :php:`\TYPO3\CMS\Extbase\Mvc\Web\Request` and :php:`\TYPO3\CMS\Extbase\Mvc\Web\Response`
+have been deprecated. Along with their deprecation, all relevant logic has been moved into their parent
+classes :php:`\TYPO3\CMS\Extbase\Mvc\Request` and :php:`\TYPO3\CMS\Extbase\Mvc\Response`.
+
+This is done to simplify the request/response handling of Extbase and to ease the transition towards
+a PSR-7 compatible handling.
+
+
+Impact
+======
+
+There is no impact yet as the "web" versions of the request and response are still used by Extbase.
+The only thing that is worth mentioning is that those who implement custom requests and/or responses,
+should derive from the non "web" versions now.
+
+
+Affected Installations
+======================
+
+All installations that implement custom request/response objects that derive from
+:php:`\TYPO3\CMS\Extbase\Mvc\Web\Request` and :php:`\TYPO3\CMS\Extbase\Mvc\Web\Response`.
+
+Those who don't change the request/response handling, will not realize this change.
+
+
+Migration
+=========
+
+As mentioned, all installations that implement custom request/response objects that derive from
+:php:`\TYPO3\CMS\Extbase\Mvc\Web\Request` and :php:`\TYPO3\CMS\Extbase\Mvc\Web\Response` should now
+derive from :php:`\TYPO3\CMS\Extbase\Mvc\Request` (and override the :php:`$format` property) and
+:php:`\TYPO3\CMS\Extbase\Mvc\Response` (and override the `:php:`shutdown` method).
+
+.. index:: PHP-API, NotScanned, ext:extbase
index 56d21c2..01692d3 100644 (file)
@@ -26,7 +26,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Configuration\RequestHandlersConfigurationFactory;
 use TYPO3\CMS\Extbase\Mvc\RequestHandlerResolver;
-use TYPO3\CMS\Extbase\Mvc\Web\Response as ExtbaseResponse;
+use TYPO3\CMS\Extbase\Mvc\Response as ExtbaseResponse;
 use TYPO3\CMS\Extbase\Persistence\ClassesConfigurationFactory;
 use TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface;
 use TYPO3\CMS\Extbase\Service\CacheService;
index 20acfbf..0faae07 100644 (file)
@@ -20,10 +20,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\MathUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
-use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
 use TYPO3\CMS\Extbase\Mvc\Web\ReferringRequest;
-use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
 use TYPO3\CMS\Extbase\Security\Cryptography\HashService;
 use TYPO3\CMS\Extbase\Validation\Validator\ConjunctionValidator;
 use TYPO3\CMS\Extbase\Validation\Validator\ValidatorInterface;
@@ -143,8 +141,9 @@ class ActionController implements ControllerInterface
             throw new \TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException(static::class . ' does not support requests of type "' . get_class($request) . '". Supported types are: ' . implode(' ', $this->supportedRequestTypes), 1187701131);
         }
 
-        if ($response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response && $request instanceof WebRequest) {
-            $response->setRequest($request);
+        $setRequestCallable = [$response, 'setRequest'];
+        if (is_callable($setRequestCallable)) {
+            $setRequestCallable($request);
         }
         $this->request = $request;
         $this->request->setDispatched(true);
@@ -751,15 +750,16 @@ class ActionController implements ControllerInterface
     public function forward($actionName, $controllerName = null, $extensionName = null, array $arguments = null)
     {
         $this->request->setDispatched(false);
-        if ($this->request instanceof WebRequest) {
-            $this->request->setControllerActionName($actionName);
-            if ($controllerName !== null) {
-                $this->request->setControllerName($controllerName);
-            }
-            if ($extensionName !== null) {
-                $this->request->setControllerExtensionName($extensionName);
-            }
+        $this->request->setControllerActionName($actionName);
+
+        if ($controllerName !== null) {
+            $this->request->setControllerName($controllerName);
         }
+
+        if ($extensionName !== null) {
+            $this->request->setControllerExtensionName($extensionName);
+        }
+
         if ($arguments !== null) {
             $this->request->setArguments($arguments);
         }
@@ -781,15 +781,11 @@ class ActionController implements ControllerInterface
      * @param int|null $pageUid Target page uid. If NULL, the current page uid is used
      * @param int $delay (optional) The delay in seconds. Default is no delay.
      * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
-     * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
      * @see forward()
      */
     protected function redirect($actionName, $controllerName = null, $extensionName = null, array $arguments = null, $pageUid = null, $delay = 0, $statusCode = 303)
     {
-        if (!$this->request instanceof WebRequest) {
-            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539734);
-        }
         if ($controllerName === null) {
             $controllerName = $this->request->getControllerName();
         }
@@ -812,24 +808,18 @@ class ActionController implements ControllerInterface
      * @param mixed $uri A string representation of a URI
      * @param int $delay (optional) The delay in seconds. Default is no delay.
      * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
-     * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
      */
     protected function redirectToUri($uri, $delay = 0, $statusCode = 303)
     {
-        if (!$this->request instanceof WebRequest) {
-            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1220539735);
-        }
-
         $this->objectManager->get(\TYPO3\CMS\Extbase\Service\CacheService::class)->clearCachesOfRegisteredPageIds();
 
         $uri = $this->addBaseUriIfNecessary($uri);
         $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
         $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . (int)$delay . ';url=' . $escapedUri . '"/></head></html>');
-        if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
-            $this->response->setStatus($statusCode);
-            $this->response->setHeader('Location', (string)$uri);
-        }
+        $this->response->setStatus($statusCode);
+        $this->response->setHeader('Location', (string)$uri);
+
         // Avoid caching the plugin when we issue a redirect response
         // This means that even when an action is configured as cachable
         // we avoid the plugin to be cached, but keep the page cache untouched
@@ -860,19 +850,13 @@ class ActionController implements ControllerInterface
      * @param int $statusCode The HTTP status code
      * @param string $statusMessage A custom HTTP status message
      * @param string $content Body content which further explains the status
-     * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
      */
     public function throwStatus($statusCode, $statusMessage = null, $content = null)
     {
-        if (!$this->request instanceof WebRequest) {
-            throw new UnsupportedRequestTypeException('throwStatus() only supports web requests.', 1220539739);
-        }
-        if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
-            $this->response->setStatus($statusCode, $statusMessage);
-            if ($content === null) {
-                $content = $this->response->getStatus();
-            }
+        $this->response->setStatus($statusCode, $statusMessage);
+        if ($content === null) {
+            $content = $this->response->getStatus();
         }
         $this->response->setContent($content);
         throw new StopActionException('throwStatus', 1476045871);
index ba83f1c..f3386ba 100644 (file)
@@ -95,6 +95,26 @@ class Request implements RequestInterface
     protected $originalRequestMappingResults;
 
     /**
+     * @var string Contains the request method
+     */
+    protected $method = 'GET';
+
+    /**
+     * @var string
+     */
+    protected $requestUri;
+
+    /**
+     * @var string The base URI for this request - ie. the host and path leading to the index.php
+     */
+    protected $baseUri;
+
+    /**
+     * @var bool TRUE if the current request is cached, false otherwise.
+     */
+    protected $isCached = false;
+
+    /**
      * Sets the dispatched flag
      *
      * @param bool $flag If this request has been dispatched
@@ -487,4 +507,93 @@ class Request implements RequestInterface
         }
         return $this->internalArguments[$argumentName];
     }
+
+    /**
+     * Sets the request method
+     *
+     * @param string $method Name of the request method
+     * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidRequestMethodException if the request method is not supported
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function setMethod($method)
+    {
+        if ($method === '' || strtoupper($method) !== $method) {
+            throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidRequestMethodException('The request method "' . $method . '" is not supported.', 1217778382);
+        }
+        $this->method = $method;
+    }
+
+    /**
+     * Returns the name of the request method
+     *
+     * @return string Name of the request method
+     */
+    public function getMethod()
+    {
+        return $this->method;
+    }
+
+    /**
+     * Sets the request URI
+     *
+     * @param string $requestUri URI of this web request
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function setRequestUri($requestUri)
+    {
+        $this->requestUri = $requestUri;
+    }
+
+    /**
+     * Returns the request URI
+     *
+     * @return string URI of this web request
+     */
+    public function getRequestUri()
+    {
+        return $this->requestUri;
+    }
+
+    /**
+     * Sets the base URI for this request.
+     *
+     * @param string $baseUri New base URI
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function setBaseUri($baseUri)
+    {
+        $this->baseUri = $baseUri;
+    }
+
+    /**
+     * Returns the base URI
+     *
+     * @return string Base URI of this web request
+     */
+    public function getBaseUri()
+    {
+        return $this->baseUri;
+    }
+
+    /**
+     * Set if the current request is cached.
+     *
+     * @param bool $isCached
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function setIsCached($isCached)
+    {
+        $this->isCached = (bool)$isCached;
+    }
+
+    /**
+     * Return whether the current request is a cached request or not.
+     *
+     * @return bool the caching status.
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function isCached()
+    {
+        return $this->isCached;
+    }
 }
index 0bad8bc..c2ac4c3 100644 (file)
@@ -14,6 +14,10 @@ namespace TYPO3\CMS\Extbase\Mvc;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Page\PageRenderer;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
+
 /**
  * A generic and very basic response implementation
  */
@@ -25,6 +29,116 @@ class Response implements \TYPO3\CMS\Extbase\Mvc\ResponseInterface
     protected $content;
 
     /**
+     * The HTTP headers which will be sent in the response
+     *
+     * @var array
+     */
+    protected $headers = [];
+
+    /**
+     * Additional header tags
+     *
+     * @var array
+     */
+    protected $additionalHeaderData = [];
+
+    /**
+     * The HTTP status code
+     *
+     * @var int
+     */
+    protected $statusCode;
+
+    /**
+     * The HTTP status message
+     *
+     * @var string
+     */
+    protected $statusMessage = 'OK';
+
+    /**
+     * The Request which generated the Response
+     *
+     * @var \TYPO3\CMS\Extbase\Mvc\Request
+     */
+    protected $request;
+
+    /**
+     * The standardized and other important HTTP Status messages
+     *
+     * @var array
+     */
+    protected $statusMessages = [
+        // INFORMATIONAL CODES
+        100 => 'Continue',
+        101 => 'Switching Protocols',
+        102 => 'Processing',
+        103 => 'Early Hints',
+        // SUCCESS CODES
+        200 => 'OK',
+        201 => 'Created',
+        202 => 'Accepted',
+        203 => 'Non-Authoritative Information',
+        204 => 'No Content',
+        205 => 'Reset Content',
+        206 => 'Partial Content',
+        207 => 'Multi-status',
+        208 => 'Already Reported',
+        226 => 'IM Used',
+        // REDIRECTION CODES
+        300 => 'Multiple Choices',
+        301 => 'Moved Permanently',
+        302 => 'Found',
+        303 => 'See Other',
+        304 => 'Not Modified',
+        305 => 'Use Proxy',
+        306 => 'Switch Proxy', // Deprecated
+        307 => 'Temporary Redirect',
+        308 => 'Permanent Redirect',
+        // CLIENT ERROR
+        400 => 'Bad Request',
+        401 => 'Unauthorized',
+        402 => 'Payment Required',
+        403 => 'Forbidden',
+        404 => 'Not Found',
+        405 => 'Method Not Allowed',
+        406 => 'Not Acceptable',
+        407 => 'Proxy Authentication Required',
+        408 => 'Request Timeout',
+        409 => 'Conflict',
+        410 => 'Gone',
+        411 => 'Length Required',
+        412 => 'Precondition Failed',
+        413 => 'Request Entity Too Large',
+        414 => 'URI Too Long',
+        415 => 'Unsupported Media Type',
+        416 => 'Requested range not satisfiable',
+        417 => 'Expectation Failed',
+        418 => 'I\'m a teapot',
+        422 => 'Unprocessable Entity',
+        423 => 'Locked',
+        424 => 'Failed Dependency',
+        425 => 'Unordered Collection',
+        426 => 'Upgrade Required',
+        428 => 'Precondition Required',
+        429 => 'Too Many Requests',
+        431 => 'Request Header Fields Too Large',
+        451 => 'Unavailable For Legal Reasons',
+        // SERVER ERROR
+        500 => 'Internal Server Error',
+        501 => 'Not Implemented',
+        502 => 'Bad Gateway',
+        503 => 'Service Unavailable',
+        504 => 'Gateway Time-out',
+        505 => 'HTTP Version not supported',
+        506 => 'Variant Also Negotiates',
+        507 => 'Insufficient Storage',
+        508 => 'Loop Detected',
+        509 => 'Bandwidth Limit Exceeded',
+        511 => 'Network Authentication Required',
+    ];
+
+    /**
      * Overrides and sets the content of the response
      *
      * @param string $content The response content
@@ -58,6 +172,7 @@ class Response implements \TYPO3\CMS\Extbase\Mvc\ResponseInterface
      * Fetches the content, returns and clears it.
      *
      * @return string
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
      */
     public function shutdown()
     {
@@ -75,4 +190,181 @@ class Response implements \TYPO3\CMS\Extbase\Mvc\ResponseInterface
     {
         return $this->getContent();
     }
+
+    /**
+     * Sets the HTTP status code and (optionally) a customized message.
+     *
+     * @param int $code The status code
+     * @param string $message If specified, this message is sent instead of the standard message
+     * @throws \InvalidArgumentException if the specified status code is not valid
+     */
+    public function setStatus($code, $message = null)
+    {
+        if (!is_int($code)) {
+            throw new \InvalidArgumentException('The HTTP status code must be of type integer, ' . gettype($code) . ' given.', 1220526013);
+        }
+        if ($message === null && !isset($this->statusMessages[$code])) {
+            throw new \InvalidArgumentException('No message found for HTTP status code "' . $code . '".', 1220526014);
+        }
+        $this->statusCode = $code;
+        $this->statusMessage = $message ?? $this->statusMessages[$code];
+    }
+
+    /**
+     * Returns status code and status message.
+     *
+     * @return string The status code and status message, eg. "404 Not Found
+     */
+    public function getStatus()
+    {
+        return $this->statusCode . ' ' . $this->statusMessage;
+    }
+
+    /**
+     * Returns the status code, if not set, uses the OK status code 200
+     *
+     * @return int
+     * @internal only use for backend module handling
+     */
+    public function getStatusCode()
+    {
+        return $this->statusCode ?: 200;
+    }
+
+    /**
+     * Sets the specified HTTP header
+     *
+     * @param string $name Name of the header, for example "Location", "Content-Description" etc.
+     * @param mixed $value The value of the given header
+     * @param bool $replaceExistingHeader If a header with the same name should be replaced. Default is TRUE.
+     * @throws \InvalidArgumentException
+     */
+    public function setHeader($name, $value, $replaceExistingHeader = true)
+    {
+        if (stripos($name, 'HTTP') === 0) {
+            throw new \InvalidArgumentException('The HTTP status header must be set via setStatus().', 1220541963);
+        }
+        if ($replaceExistingHeader === true || !isset($this->headers[$name])) {
+            $this->headers[$name] = [$value];
+        } else {
+            $this->headers[$name][] = $value;
+        }
+    }
+
+    /**
+     * Returns the HTTP headers - including the status header - of this web response
+     *
+     * @return string[] The HTTP headers
+     */
+    public function getHeaders()
+    {
+        $preparedHeaders = [];
+        if ($this->statusCode !== null) {
+            $protocolVersion = $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0';
+            $statusHeader = $protocolVersion . ' ' . $this->statusCode . ' ' . $this->statusMessage;
+            $preparedHeaders[] = $statusHeader;
+        }
+        foreach ($this->headers as $name => $values) {
+            foreach ($values as $value) {
+                $preparedHeaders[] = $name . ': ' . $value;
+            }
+        }
+        return $preparedHeaders;
+    }
+
+    /**
+     * Returns the HTTP headers grouped by name without the status header
+     *
+     * @return array all headers set for this request
+     * @internal only used within TYPO3 Core to convert to PSR-7 response headers
+     */
+    public function getUnpreparedHeaders(): array
+    {
+        return $this->headers;
+    }
+
+    /**
+     * Sends the HTTP headers.
+     *
+     * If headers have already been sent, this method fails silently.
+     */
+    public function sendHeaders()
+    {
+        if (headers_sent() === true) {
+            return;
+        }
+        foreach ($this->getHeaders() as $header) {
+            header($header);
+        }
+    }
+
+    /**
+     * Renders and sends the whole web response
+     */
+    public function send()
+    {
+        $this->sendHeaders();
+        if ($this->content !== null) {
+            echo $this->getContent();
+        }
+    }
+
+    /**
+     * Adds an additional header data (something like
+     * '<script src="myext/Resources/JavaScript/my.js"></script>'
+     * )
+     *
+     * @TODO The workaround and the $request member should be removed again, once the PageRender does support non-cached USER_INTs
+     * @param string $additionalHeaderData The value additional header
+     * @throws \InvalidArgumentException
+     */
+    public function addAdditionalHeaderData($additionalHeaderData)
+    {
+        if (!is_string($additionalHeaderData)) {
+            throw new \InvalidArgumentException('The additiona header data must be of type String, ' . gettype($additionalHeaderData) . ' given.', 1237370877);
+        }
+        if ($this->request->isCached()) {
+            /** @var PageRenderer $pageRenderer */
+            $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
+            $pageRenderer->addHeaderData($additionalHeaderData);
+        } else {
+            $this->additionalHeaderData[] = $additionalHeaderData;
+        }
+    }
+
+    /**
+     * Returns the additional header data
+     *
+     * @return array The additional header data
+     */
+    public function getAdditionalHeaderData()
+    {
+        return $this->additionalHeaderData;
+    }
+
+    /**
+     * @param \TYPO3\CMS\Extbase\Mvc\Request $request
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function setRequest(\TYPO3\CMS\Extbase\Mvc\Request $request)
+    {
+        $this->request = $request;
+    }
+
+    /**
+     * @return \TYPO3\CMS\Extbase\Mvc\Request
+     * @internal only to be used within Extbase, not part of TYPO3 Core API.
+     */
+    public function getRequest()
+    {
+        return $this->request;
+    }
+
+    /**
+     * @return TypoScriptFrontendController
+     */
+    protected function getTypoScriptFrontendController()
+    {
+        return $GLOBALS['TSFE'];
+    }
 }
index 9b54516..b2b7f26 100644 (file)
@@ -16,7 +16,6 @@ namespace TYPO3\CMS\Extbase\Mvc\View;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Extbase\Mvc\Web\Response as WebResponse;
 use TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface;
 use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
 use TYPO3\CMS\Extbase\Reflection\ReflectionService;
@@ -212,24 +211,22 @@ class JsonView extends AbstractView
     public function render(): string
     {
         $response = $this->controllerContext->getResponse();
-        if ($response instanceof WebResponse) {
-            // @todo Ticket: #63643 This should be solved differently once request/response model is available for TSFE.
-            if (!empty($GLOBALS['TSFE']) && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
-                /** @var TypoScriptFrontendController $typoScriptFrontendController */
-                $typoScriptFrontendController = $GLOBALS['TSFE'];
-                if (empty($typoScriptFrontendController->config['config']['disableCharsetHeader'])) {
-                    // If the charset header is *not* disabled in configuration,
-                    // TypoScriptFrontendController will send the header later with the Content-Type which we set here.
-                    $typoScriptFrontendController->setContentType('application/json');
-                } else {
-                    // Although the charset header is disabled in configuration, we *must* send a Content-Type header here.
-                    // Content-Type headers optionally carry charset information at the same time.
-                    // Since we have the information about the charset, there is no reason to not include the charset information although disabled in TypoScript.
-                    $response->setHeader('Content-Type', 'application/json; charset=' . trim($typoScriptFrontendController->metaCharset));
-                }
+        // @todo Ticket: #63643 This should be solved differently once request/response model is available for TSFE.
+        if (!empty($GLOBALS['TSFE']) && $GLOBALS['TSFE'] instanceof TypoScriptFrontendController) {
+            /** @var TypoScriptFrontendController $typoScriptFrontendController */
+            $typoScriptFrontendController = $GLOBALS['TSFE'];
+            if (empty($typoScriptFrontendController->config['config']['disableCharsetHeader'])) {
+                // If the charset header is *not* disabled in configuration,
+                // TypoScriptFrontendController will send the header later with the Content-Type which we set here.
+                $typoScriptFrontendController->setContentType('application/json');
             } else {
-                $response->setHeader('Content-Type', 'application/json');
+                // Although the charset header is disabled in configuration, we *must* send a Content-Type header here.
+                // Content-Type headers optionally carry charset information at the same time.
+                // Since we have the information about the charset, there is no reason to not include the charset information although disabled in TypoScript.
+                $response->setHeader('Content-Type', 'application/json; charset=' . trim($typoScriptFrontendController->metaCharset));
             }
+        } else {
+            $response->setHeader('Content-Type', 'application/json');
         }
         $propertiesToRender = $this->renderArray();
         return json_encode($propertiesToRender, JSON_UNESCAPED_UNICODE);
index 0016ab7..92a1322 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Extbase\Mvc\Web;
 
 /**
  * Represents a web request.
+ * @deprecated since TYPO3 10.2, will be removed in version 11.0.
  */
 class Request extends \TYPO3\CMS\Extbase\Mvc\Request
 {
@@ -23,113 +24,4 @@ class Request extends \TYPO3\CMS\Extbase\Mvc\Request
      * @var string The requested representation format
      */
     protected $format = 'html';
-
-    /**
-     * @var string Contains the request method
-     */
-    protected $method = 'GET';
-
-    /**
-     * @var string
-     */
-    protected $requestUri;
-
-    /**
-     * @var string The base URI for this request - ie. the host and path leading to the index.php
-     */
-    protected $baseUri;
-
-    /**
-     * @var bool TRUE if the current request is cached, false otherwise.
-     */
-    protected $isCached = false;
-
-    /**
-     * Sets the request method
-     *
-     * @param string $method Name of the request method
-     * @throws \TYPO3\CMS\Extbase\Mvc\Exception\InvalidRequestMethodException if the request method is not supported
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function setMethod($method)
-    {
-        if ($method === '' || strtoupper($method) !== $method) {
-            throw new \TYPO3\CMS\Extbase\Mvc\Exception\InvalidRequestMethodException('The request method "' . $method . '" is not supported.', 1217778382);
-        }
-        $this->method = $method;
-    }
-
-    /**
-     * Returns the name of the request method
-     *
-     * @return string Name of the request method
-     */
-    public function getMethod()
-    {
-        return $this->method;
-    }
-
-    /**
-     * Sets the request URI
-     *
-     * @param string $requestUri URI of this web request
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function setRequestUri($requestUri)
-    {
-        $this->requestUri = $requestUri;
-    }
-
-    /**
-     * Returns the request URI
-     *
-     * @return string URI of this web request
-     */
-    public function getRequestUri()
-    {
-        return $this->requestUri;
-    }
-
-    /**
-     * Sets the base URI for this request.
-     *
-     * @param string $baseUri New base URI
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function setBaseUri($baseUri)
-    {
-        $this->baseUri = $baseUri;
-    }
-
-    /**
-     * Returns the base URI
-     *
-     * @return string Base URI of this web request
-     */
-    public function getBaseUri()
-    {
-        return $this->baseUri;
-    }
-
-    /**
-     * Set if the current request is cached.
-     *
-     * @param bool $isCached
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function setIsCached($isCached)
-    {
-        $this->isCached = (bool)$isCached;
-    }
-
-    /**
-     * Return whether the current request is a cached request or not.
-     *
-     * @return bool the caching status.
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function isCached()
-    {
-        return $this->isCached;
-    }
 }
index 94e8008..e3e1315 100644 (file)
@@ -15,12 +15,10 @@ namespace TYPO3\CMS\Extbase\Mvc\Web;
  */
 
 use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
-use TYPO3\CMS\Core\Page\PageRenderer;
-use TYPO3\CMS\Core\Utility\GeneralUtility;
-use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
 
 /**
  * A web specific response implementation
+ * @deprecated since TYPO3 10.2, will be removed in version 11.0.
  */
 class Response extends \TYPO3\CMS\Extbase\Mvc\Response
 {
@@ -34,116 +32,6 @@ class Response extends \TYPO3\CMS\Extbase\Mvc\Response
     ];
 
     /**
-     * The HTTP headers which will be sent in the response
-     *
-     * @var array
-     */
-    protected $headers = [];
-
-    /**
-     * Additional header tags
-     *
-     * @var array
-     */
-    protected $additionalHeaderData = [];
-
-    /**
-     * The HTTP status code
-     *
-     * @var int
-     */
-    protected $statusCode;
-
-    /**
-     * The HTTP status message
-     *
-     * @var string
-     */
-    protected $statusMessage = 'OK';
-
-    /**
-     * The Request which generated the Response
-     *
-     * @var \TYPO3\CMS\Extbase\Mvc\Web\Request
-     */
-    protected $request;
-
-    /**
-     * The standardized and other important HTTP Status messages
-     *
-     * @var array
-     */
-    protected $statusMessages = [
-        // INFORMATIONAL CODES
-        100 => 'Continue',
-        101 => 'Switching Protocols',
-        102 => 'Processing',
-        103 => 'Early Hints',
-        // SUCCESS CODES
-        200 => 'OK',
-        201 => 'Created',
-        202 => 'Accepted',
-        203 => 'Non-Authoritative Information',
-        204 => 'No Content',
-        205 => 'Reset Content',
-        206 => 'Partial Content',
-        207 => 'Multi-status',
-        208 => 'Already Reported',
-        226 => 'IM Used',
-        // REDIRECTION CODES
-        300 => 'Multiple Choices',
-        301 => 'Moved Permanently',
-        302 => 'Found',
-        303 => 'See Other',
-        304 => 'Not Modified',
-        305 => 'Use Proxy',
-        306 => 'Switch Proxy', // Deprecated
-        307 => 'Temporary Redirect',
-        308 => 'Permanent Redirect',
-        // CLIENT ERROR
-        400 => 'Bad Request',
-        401 => 'Unauthorized',
-        402 => 'Payment Required',
-        403 => 'Forbidden',
-        404 => 'Not Found',
-        405 => 'Method Not Allowed',
-        406 => 'Not Acceptable',
-        407 => 'Proxy Authentication Required',
-        408 => 'Request Timeout',
-        409 => 'Conflict',
-        410 => 'Gone',
-        411 => 'Length Required',
-        412 => 'Precondition Failed',
-        413 => 'Request Entity Too Large',
-        414 => 'URI Too Long',
-        415 => 'Unsupported Media Type',
-        416 => 'Requested range not satisfiable',
-        417 => 'Expectation Failed',
-        418 => 'I\'m a teapot',
-        422 => 'Unprocessable Entity',
-        423 => 'Locked',
-        424 => 'Failed Dependency',
-        425 => 'Unordered Collection',
-        426 => 'Upgrade Required',
-        428 => 'Precondition Required',
-        429 => 'Too Many Requests',
-        431 => 'Request Header Fields Too Large',
-        451 => 'Unavailable For Legal Reasons',
-        // SERVER ERROR
-        500 => 'Internal Server Error',
-        501 => 'Not Implemented',
-        502 => 'Bad Gateway',
-        503 => 'Service Unavailable',
-        504 => 'Gateway Time-out',
-        505 => 'HTTP Version not supported',
-        506 => 'Variant Also Negotiates',
-        507 => 'Insufficient Storage',
-        508 => 'Loop Detected',
-        509 => 'Bandwidth Limit Exceeded',
-        511 => 'Network Authentication Required',
-    ];
-
-    /**
      * @var \TYPO3\CMS\Extbase\Service\EnvironmentService
      * @deprecated
      */
@@ -160,175 +48,6 @@ class Response extends \TYPO3\CMS\Extbase\Mvc\Response
     }
 
     /**
-     * Sets the HTTP status code and (optionally) a customized message.
-     *
-     * @param int $code The status code
-     * @param string $message If specified, this message is sent instead of the standard message
-     * @throws \InvalidArgumentException if the specified status code is not valid
-     */
-    public function setStatus($code, $message = null)
-    {
-        if (!is_int($code)) {
-            throw new \InvalidArgumentException('The HTTP status code must be of type integer, ' . gettype($code) . ' given.', 1220526013);
-        }
-        if ($message === null && !isset($this->statusMessages[$code])) {
-            throw new \InvalidArgumentException('No message found for HTTP status code "' . $code . '".', 1220526014);
-        }
-        $this->statusCode = $code;
-        $this->statusMessage = $message ?? $this->statusMessages[$code];
-    }
-
-    /**
-     * Returns status code and status message.
-     *
-     * @return string The status code and status message, eg. "404 Not Found
-     */
-    public function getStatus()
-    {
-        return $this->statusCode . ' ' . $this->statusMessage;
-    }
-
-    /**
-     * Returns the status code, if not set, uses the OK status code 200
-     *
-     * @return int
-     * @internal only use for backend module handling
-     */
-    public function getStatusCode()
-    {
-        return $this->statusCode ?: 200;
-    }
-
-    /**
-     * Sets the specified HTTP header
-     *
-     * @param string $name Name of the header, for example "Location", "Content-Description" etc.
-     * @param mixed $value The value of the given header
-     * @param bool $replaceExistingHeader If a header with the same name should be replaced. Default is TRUE.
-     * @throws \InvalidArgumentException
-     */
-    public function setHeader($name, $value, $replaceExistingHeader = true)
-    {
-        if (stripos($name, 'HTTP') === 0) {
-            throw new \InvalidArgumentException('The HTTP status header must be set via setStatus().', 1220541963);
-        }
-        if ($replaceExistingHeader === true || !isset($this->headers[$name])) {
-            $this->headers[$name] = [$value];
-        } else {
-            $this->headers[$name][] = $value;
-        }
-    }
-
-    /**
-     * Returns the HTTP headers - including the status header - of this web response
-     *
-     * @return string[] The HTTP headers
-     */
-    public function getHeaders()
-    {
-        $preparedHeaders = [];
-        if ($this->statusCode !== null) {
-            $protocolVersion = $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0';
-            $statusHeader = $protocolVersion . ' ' . $this->statusCode . ' ' . $this->statusMessage;
-            $preparedHeaders[] = $statusHeader;
-        }
-        foreach ($this->headers as $name => $values) {
-            foreach ($values as $value) {
-                $preparedHeaders[] = $name . ': ' . $value;
-            }
-        }
-        return $preparedHeaders;
-    }
-
-    /**
-     * Returns the HTTP headers grouped by name without the status header
-     *
-     * @return array all headers set for this request
-     * @internal only used within TYPO3 Core to convert to PSR-7 response headers
-     */
-    public function getUnpreparedHeaders(): array
-    {
-        return $this->headers;
-    }
-
-    /**
-     * Sends the HTTP headers.
-     *
-     * If headers have already been sent, this method fails silently.
-     */
-    public function sendHeaders()
-    {
-        if (headers_sent() === true) {
-            return;
-        }
-        foreach ($this->getHeaders() as $header) {
-            header($header);
-        }
-    }
-
-    /**
-     * Renders and sends the whole web response
-     */
-    public function send()
-    {
-        $this->sendHeaders();
-        if ($this->content !== null) {
-            echo $this->getContent();
-        }
-    }
-
-    /**
-     * Adds an additional header data (something like
-     * '<script src="myext/Resources/JavaScript/my.js"></script>'
-     * )
-     *
-     * @TODO The workaround and the $request member should be removed again, once the PageRender does support non-cached USER_INTs
-     * @param string $additionalHeaderData The value additional header
-     * @throws \InvalidArgumentException
-     */
-    public function addAdditionalHeaderData($additionalHeaderData)
-    {
-        if (!is_string($additionalHeaderData)) {
-            throw new \InvalidArgumentException('The additiona header data must be of type String, ' . gettype($additionalHeaderData) . ' given.', 1237370877);
-        }
-        if ($this->request->isCached()) {
-            /** @var PageRenderer $pageRenderer */
-            $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
-            $pageRenderer->addHeaderData($additionalHeaderData);
-        } else {
-            $this->additionalHeaderData[] = $additionalHeaderData;
-        }
-    }
-
-    /**
-     * Returns the additional header data
-     *
-     * @return array The additional header data
-     */
-    public function getAdditionalHeaderData()
-    {
-        return $this->additionalHeaderData;
-    }
-
-    /**
-     * @param \TYPO3\CMS\Extbase\Mvc\Web\Request $request
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function setRequest(\TYPO3\CMS\Extbase\Mvc\Web\Request $request)
-    {
-        $this->request = $request;
-    }
-
-    /**
-     * @return \TYPO3\CMS\Extbase\Mvc\Web\Request
-     * @internal only to be used within Extbase, not part of TYPO3 Core API.
-     */
-    public function getRequest()
-    {
-        return $this->request;
-    }
-
-    /**
      * Sends additional headers and returns the content
      *
      * @return string|null
@@ -342,12 +61,4 @@ class Response extends \TYPO3\CMS\Extbase\Mvc\Response
         $this->sendHeaders();
         return parent::shutdown();
     }
-
-    /**
-     * @return TypoScriptFrontendController
-     */
-    protected function getTypoScriptFrontendController()
-    {
-        return $GLOBALS['TSFE'];
-    }
 }
index 7fe705f..3a58625 100644 (file)
@@ -22,7 +22,6 @@ use TYPO3\CMS\Core\Utility\ArrayUtility;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Core\Utility\HttpUtility;
 use TYPO3\CMS\Extbase\Mvc\Request;
-use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
 
 /**
  * An URI Builder
@@ -685,14 +684,14 @@ class UriBuilder
         unset($arguments['route'], $arguments['token']);
         $backendUriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
         try {
-            if ($this->request instanceof WebRequest && $this->createAbsoluteUri) {
+            if ($this->createAbsoluteUri) {
                 $uri = (string)$backendUriBuilder->buildUriFromRoutePath($routeName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_URL);
             } else {
                 $uri = (string)$backendUriBuilder->buildUriFromRoutePath($routeName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_PATH);
             }
         } catch (ResourceNotFoundException $e) {
             try {
-                if ($this->request instanceof WebRequest && $this->createAbsoluteUri) {
+                if ($this->createAbsoluteUri) {
                     $uri = (string)$backendUriBuilder->buildUriFromRoute($routeName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_URL);
                 } else {
                     $uri = (string)$backendUriBuilder->buildUriFromRoute($routeName, $arguments, \TYPO3\CMS\Backend\Routing\UriBuilder::ABSOLUTE_PATH);
index f90a1ca..6a02b88 100644 (file)
@@ -18,9 +18,14 @@ namespace TYPO3\CMS\Fluid\Core\Widget;
  * Represents a widget request.
  * @internal It is a purely internal class which should not be used outside of Fluid.
  */
-class WidgetRequest extends \TYPO3\CMS\Extbase\Mvc\Web\Request
+class WidgetRequest extends \TYPO3\CMS\Extbase\Mvc\Request
 {
     /**
+     * @var string The requested representation format
+     */
+    protected $format = 'html';
+
+    /**
      * @var \TYPO3\CMS\Fluid\Core\Widget\WidgetContext
      */
     protected $widgetContext;
index 2c61b90..619a341 100644 (file)
@@ -17,7 +17,6 @@ namespace TYPO3\CMS\Fluid\View;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Mvc\Controller\ControllerContext;
-use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\Extbase\Object\ObjectManager;
 use TYPO3\CMS\Extbase\Service\EnvironmentService;
@@ -60,8 +59,8 @@ class StandaloneView extends AbstractTemplateView
             $baseUri .= TYPO3_mainDir;
         }
 
-        /** @var WebRequest $request */
-        $request = $this->objectManager->get(WebRequest::class);
+        /** @var \TYPO3\CMS\Extbase\Mvc\Web\Request $request */
+        $request = $this->objectManager->get(\TYPO3\CMS\Extbase\Mvc\Web\Request::class);
         $request->setRequestUri(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'));
         $request->setBaseUri($baseUri);
         /** @var UriBuilder $uriBuilder */
@@ -109,7 +108,7 @@ class StandaloneView extends AbstractTemplateView
     /**
      * Returns the current request object
      *
-     * @return WebRequest
+     * @return \TYPO3\CMS\Extbase\Mvc\Request
      * @throws \RuntimeException
      * @internal
      */
index ad33a8a..b767a01 100644 (file)
@@ -17,8 +17,6 @@ namespace TYPO3\CMS\Form\Domain\Finishers;
 
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\Exception\StopActionException;
-use TYPO3\CMS\Extbase\Mvc\Exception\UnsupportedRequestTypeException;
-use TYPO3\CMS\Extbase\Mvc\Web\Request;
 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 
 /**
@@ -88,15 +86,10 @@ class RedirectFinisher extends AbstractFinisher
      * @param string $additionalParameters
      * @param int $delay (optional) The delay in seconds. Default is no delay.
      * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
-     * @throws UnsupportedRequestTypeException If the request is not a web request
      * @see forward()
      */
     protected function redirect(int $pageUid = 1, string $additionalParameters = '', int $delay = 0, int $statusCode = 303)
     {
-        if (!$this->request instanceof Request) {
-            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1471776457);
-        }
-
         $typolinkConfiguration = [
             'parameter' => $pageUid,
             'additionalParams' => $additionalParameters,
@@ -113,23 +106,16 @@ class RedirectFinisher extends AbstractFinisher
      * @param string $uri A string representation of a URI
      * @param int $delay (optional) The delay in seconds. Default is no delay.
      * @param int $statusCode (optional) The HTTP status code for the redirect. Default is "303 See Other
-     * @throws UnsupportedRequestTypeException If the request is not a web request
      * @throws StopActionException
      */
     protected function redirectToUri(string $uri, int $delay = 0, int $statusCode = 303)
     {
-        if (!$this->request instanceof Request) {
-            throw new UnsupportedRequestTypeException('redirect() only supports web requests.', 1471776458);
-        }
-
         $uri = $this->addBaseUriIfNecessary($uri);
         $escapedUri = htmlentities($uri, ENT_QUOTES, 'utf-8');
 
         $this->response->setContent('<html><head><meta http-equiv="refresh" content="' . (int)$delay . ';url=' . $escapedUri . '"/></head></html>');
-        if ($this->response instanceof \TYPO3\CMS\Extbase\Mvc\Web\Response) {
-            $this->response->setStatus($statusCode);
-            $this->response->setHeader('Location', (string)$uri);
-        }
+        $this->response->setStatus($statusCode);
+        $this->response->setHeader('Location', (string)$uri);
         throw new StopActionException('redirectToUri', 1477070964);
     }
 
index 485640b..52b75c8 100644 (file)
@@ -23,8 +23,8 @@ use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Type\Bitmask\Permission;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+use TYPO3\CMS\Extbase\Mvc\Request;
 use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
-use TYPO3\CMS\Extbase\Mvc\Web\Request as WebRequest;
 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
 use TYPO3\CMS\IndexedSearch\Domain\Repository\AdministrationRepository;
 use TYPO3\CMS\IndexedSearch\Indexer;
@@ -188,7 +188,7 @@ class AdministrationController extends ActionController
             $beUser->uc['indexed_search']['arguments'] = $request->getArguments();
             $beUser->writeUC();
         } elseif (isset($beUser->uc['indexed_search']['action'])) {
-            if ($request instanceof WebRequest) {
+            if ($request instanceof Request) {
                 $request->setControllerActionName($beUser->uc['indexed_search']['action']);
             }
             if (isset($beUser->uc['indexed_search']['arguments'])) {