[TASK] Ensure HTTP RequestHandlers always return a PSR-7 Repsonse
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Http / RequestHandler.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Http;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use TYPO3\CMS\Backend\Routing\Exception\InvalidRequestTokenException;
21 use TYPO3\CMS\Core\Core\Bootstrap;
22 use TYPO3\CMS\Core\Http\RedirectResponse;
23 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
24 use TYPO3\CMS\Core\Http\Response;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26
27 /**
28 * General RequestHandler for the TYPO3 Backend. This is used for all Backend requests except for CLI
29 * or AJAX calls.
30 *
31 * If a get/post parameter "route" is set, the Backend Routing is called and searches for a
32 * matching route inside the Router. The corresponding controller / action is called then which returns the response.
33 *
34 * The following get/post parameters are evaluated here:
35 * - route
36 * - token
37 */
38 class RequestHandler implements RequestHandlerInterface
39 {
40 /**
41 * Instance of the current TYPO3 bootstrap
42 * @var Bootstrap
43 */
44 protected $bootstrap;
45
46 /**
47 * Constructor handing over the bootstrap and the original request
48 *
49 * @param Bootstrap $bootstrap
50 */
51 public function __construct(Bootstrap $bootstrap)
52 {
53 $this->bootstrap = $bootstrap;
54 }
55
56 /**
57 * Handles any backend request
58 *
59 * @param ServerRequestInterface $request
60 * @return ResponseInterface
61 */
62 public function handleRequest(ServerRequestInterface $request): ResponseInterface
63 {
64 // Check if a module URL is requested and deprecate this call
65 $moduleName = $request->getQueryParams()['M'] ?? $request->getParsedBody()['M'] ?? null;
66 // Allow the login page to be displayed if routing is not used and on index.php
67 $pathToRoute = $request->getQueryParams()['route'] ?? $request->getParsedBody()['route'] ?? $moduleName ?? '/login';
68 $request = $request->withAttribute('routePath', $pathToRoute);
69
70 // skip the BE user check on the login page
71 // should be handled differently in the future by checking the Bootstrap directly
72 $this->boot($pathToRoute === '/login');
73
74 if ($moduleName !== null) {
75 trigger_error('Calling the TYPO3 Backend with "M" GET parameter will be removed in TYPO3 v10,'
76 . ' the calling code calls this script with "&M=' . $moduleName . '" and needs to be adapted'
77 . ' to use the TYPO3 API.', E_USER_DEPRECATED);
78 }
79
80 // Check if the router has the available route and dispatch.
81 try {
82 return $this->dispatch($request);
83 } catch (InvalidRequestTokenException $e) {
84 // When token was invalid redirect to login
85 $url = GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir;
86 return new RedirectResponse($url);
87 }
88 }
89
90 /**
91 * Does the main work for setting up the backend environment for any Backend request
92 *
93 * @param bool $proceedIfNoUserIsLoggedIn option to allow to render the request even if no user is logged in
94 */
95 protected function boot(bool $proceedIfNoUserIsLoggedIn)
96 {
97 $this->bootstrap
98 ->checkLockedBackendAndRedirectOrDie()
99 ->checkBackendIpOrDie()
100 ->checkSslBackendAndRedirectIfNeeded()
101 ->initializeBackendRouter()
102 ->loadExtTables()
103 ->initializeBackendUser()
104 ->initializeBackendAuthentication($proceedIfNoUserIsLoggedIn)
105 ->initializeLanguageObject()
106 ->initializeBackendTemplate()
107 ->endOutputBufferingAndCleanPreviousOutput()
108 ->initializeOutputCompression()
109 ->sendHttpHeaders();
110 }
111
112 /**
113 * This request handler can handle any backend request (but not CLI).
114 *
115 * @param ServerRequestInterface $request
116 * @return bool If the request is not a CLI script, TRUE otherwise FALSE
117 */
118 public function canHandleRequest(ServerRequestInterface $request): bool
119 {
120 return TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_BE && !(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI);
121 }
122
123 /**
124 * Returns the priority - how eager the handler is to actually handle the
125 * request.
126 *
127 * @return int The priority of the request handler.
128 */
129 public function getPriority(): int
130 {
131 return 50;
132 }
133
134 /**
135 * Dispatch the request to the appropriate controller through the Backend Dispatcher which resolves the routing
136 *
137 * @param ServerRequestInterface $request
138 * @return ResponseInterface
139 * @throws InvalidRequestTokenException if the request could not be verified
140 * @throws \InvalidArgumentException when a route is found but the target of the route cannot be called
141 */
142 protected function dispatch(ServerRequestInterface $request): ResponseInterface
143 {
144 /** @var Response $response */
145 $response = GeneralUtility::makeInstance(Response::class);
146 /** @var RouteDispatcher $dispatcher */
147 $dispatcher = GeneralUtility::makeInstance(RouteDispatcher::class);
148 return $dispatcher->dispatch($request, $response);
149 }
150 }