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