[TASK] Ensure HTTP RequestHandlers always return a PSR-7 Repsonse
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Http / EidRequestHandler.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Frontend\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\Core\Core\Bootstrap;
21 use TYPO3\CMS\Core\Exception;
22 use TYPO3\CMS\Core\Http\Dispatcher;
23 use TYPO3\CMS\Core\Http\NullResponse;
24 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
25 use TYPO3\CMS\Core\Http\Response;
26 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
27 use TYPO3\CMS\Core\Utility\GeneralUtility;
28
29 /**
30 * Lightweight alternative to the regular RequestHandler used when $_GET[eID] is set.
31 * In the future, logic from the EidUtility will be moved to this class.
32 */
33 class EidRequestHandler implements RequestHandlerInterface
34 {
35 /**
36 * Instance of the current TYPO3 bootstrap
37 * @var Bootstrap
38 */
39 protected $bootstrap;
40
41 /**
42 * Constructor handing over the bootstrap and the original request
43 *
44 * @param Bootstrap $bootstrap
45 */
46 public function __construct(Bootstrap $bootstrap)
47 {
48 $this->bootstrap = $bootstrap;
49 }
50
51 /**
52 * Handles a frontend request based on the _GP "eID" variable.
53 *
54 * @param ServerRequestInterface $request
55 * @return ResponseInterface
56 */
57 public function handleRequest(ServerRequestInterface $request): ResponseInterface
58 {
59 // Starting time tracking
60 $configuredCookieName = trim($GLOBALS['TYPO3_CONF_VARS']['BE']['cookieName']) ?: 'be_typo_user';
61
62 /** @var TimeTracker $timeTracker */
63 $timeTracker = GeneralUtility::makeInstance(TimeTracker::class, ($request->getCookieParams()[$configuredCookieName] ? true : false));
64 $timeTracker->start();
65
66 // Hook to preprocess the current request
67 foreach ($GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['tslib/index_ts.php']['preprocessRequest'] ?? [] as $hookFunction) {
68 $hookParameters = [];
69 GeneralUtility::callUserFunction($hookFunction, $hookParameters, $hookParameters);
70 }
71
72 // Remove any output produced until now
73 $this->bootstrap->endOutputBufferingAndCleanPreviousOutput();
74 return $this->dispatch($request);
75 }
76
77 /**
78 * This request handler can handle any frontend request.
79 *
80 * @param ServerRequestInterface $request The request to process
81 * @return bool If the request is not an eID request, TRUE otherwise FALSE
82 */
83 public function canHandleRequest(ServerRequestInterface $request): bool
84 {
85 return !empty($request->getQueryParams()['eID']) || !empty($request->getParsedBody()['eID']);
86 }
87
88 /**
89 * Returns the priority - how eager the handler is to actually handle the
90 * request.
91 *
92 * @return int The priority of the request handler.
93 */
94 public function getPriority(): int
95 {
96 return 80;
97 }
98
99 /**
100 * Dispatches the request to the corresponding eID class or eID script
101 *
102 * @param ServerRequestInterface $request
103 * @return ResponseInterface
104 * @throws Exception
105 */
106 protected function dispatch(ServerRequestInterface $request): ResponseInterface
107 {
108 /** @var Response $response */
109 $response = GeneralUtility::makeInstance(Response::class);
110
111 $eID = $request->getParsedBody()['eID'] ?? $request->getQueryParams()['eID'] ?? '';
112
113 if (empty($eID) || !isset($GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include'][$eID])) {
114 return $response->withStatus(404, 'eID not registered');
115 }
116
117 $configuration = $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include'][$eID];
118
119 // Simple check to make sure that it's not an absolute file (to use the fallback)
120 if (strpos($configuration, '::') !== false || is_callable($configuration)) {
121 /** @var Dispatcher $dispatcher */
122 $dispatcher = GeneralUtility::makeInstance(Dispatcher::class);
123 $request = $request->withAttribute('target', $configuration);
124 return $dispatcher->dispatch($request, $response);
125 }
126
127 $scriptPath = GeneralUtility::getFileAbsFileName($configuration);
128 if ($scriptPath === '') {
129 throw new Exception('Registered eID has invalid script path.', 1416391467);
130 }
131 include $scriptPath;
132 return new NullResponse();
133 }
134 }