e2145c7a3e67d850ae864523728cfbcf1be70c9e
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Http / AjaxRequestHandler.php
1 <?php
2 namespace TYPO3\CMS\Backend\Http;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use Psr\Http\Message\ResponseInterface;
18 use Psr\Http\Message\ServerRequestInterface;
19 use TYPO3\CMS\Backend\Routing\Exception\InvalidRequestTokenException;
20 use TYPO3\CMS\Backend\Routing\Exception\ResourceNotFoundException;
21 use TYPO3\CMS\Core\Core\Bootstrap;
22 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
23 use TYPO3\CMS\Core\Http\Response;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25
26 /**
27 * AJAX dispatcher
28 *
29 * Main entry point for AJAX calls in the TYPO3 Backend. Based on ?route=/ajax/* of the outside application.
30 * Before doing the basic BE-related set up of this request (see the additional calls on $this->bootstrap inside
31 * handleRequest()), some AJAX-calls can be made without a valid user, which is determined here.
32 *
33 * AJAX Requests are typically registered within EXT:myext/Configuration/Backend/AjaxRoutes.php
34 */
35 class AjaxRequestHandler implements RequestHandlerInterface
36 {
37 /**
38 * Instance of the current TYPO3 bootstrap
39 * @var Bootstrap
40 */
41 protected $bootstrap;
42
43 /**
44 * List of requests that don't need a valid BE user
45 * @var array
46 */
47 protected $publicAjaxRoutes = [
48 '/ajax/login',
49 '/ajax/logout',
50 '/ajax/login/refresh',
51 '/ajax/login/timedout',
52 '/ajax/rsa/publickey'
53 ];
54
55 /**
56 * Constructor handing over the bootstrap and the original request
57 *
58 * @param Bootstrap $bootstrap
59 */
60 public function __construct(Bootstrap $bootstrap)
61 {
62 $this->bootstrap = $bootstrap;
63 }
64
65 /**
66 * Handles any AJAX request in the TYPO3 Backend
67 *
68 * @param ServerRequestInterface $request
69 * @return NULL|\Psr\Http\Message\ResponseInterface
70 */
71 public function handleRequest(ServerRequestInterface $request)
72 {
73 // First get the name of the route
74 $routePath = isset($request->getParsedBody()['route']) ? $request->getParsedBody()['route'] : $request->getQueryParams()['route'];
75 $request = $request->withAttribute('routePath', $routePath);
76
77 $proceedIfNoUserIsLoggedIn = $this->isLoggedInBackendUserRequired($routePath);
78 $this->boot($proceedIfNoUserIsLoggedIn);
79
80 // Backend Routing - check if a valid route is there, and dispatch
81 return $this->dispatch($request);
82 }
83
84 /**
85 * This request handler can handle any backend request having
86 * an /ajax/ request
87 *
88 * @param ServerRequestInterface $request
89 * @return bool If the request is an AJAX backend request, TRUE otherwise FALSE
90 */
91 public function canHandleRequest(ServerRequestInterface $request)
92 {
93 $routePath = isset($request->getParsedBody()['route']) ? $request->getParsedBody()['route'] : $request->getQueryParams()['route'];
94 return strpos($routePath, '/ajax/') === 0;
95 }
96
97 /**
98 * Returns the priority - how eager the handler is to actually handle the request.
99 *
100 * @return int The priority of the request handler.
101 */
102 public function getPriority()
103 {
104 return 80;
105 }
106
107 /**
108 * Check if the user is required for the request
109 * If we're trying to do an ajax login, don't require a user
110 *
111 * @param string $routePath the Route path to check against, something like '
112 * @return bool whether the request can proceed without a login required
113 */
114 protected function isLoggedInBackendUserRequired($routePath)
115 {
116 return in_array($routePath, $this->publicAjaxRoutes, true);
117 }
118
119 /**
120 * Start the Backend bootstrap part
121 *
122 * @param bool $proceedIfNoUserIsLoggedIn a flag if a backend user is required
123 */
124 protected function boot($proceedIfNoUserIsLoggedIn)
125 {
126 $this->bootstrap
127 ->checkLockedBackendAndRedirectOrDie($proceedIfNoUserIsLoggedIn)
128 ->checkBackendIpOrDie()
129 ->checkSslBackendAndRedirectIfNeeded()
130 ->initializeBackendRouter()
131 ->loadExtTables()
132 ->initializeBackendUser()
133 ->initializeBackendAuthentication($proceedIfNoUserIsLoggedIn)
134 ->initializeLanguageObject()
135 ->initializeBackendTemplate()
136 ->endOutputBufferingAndCleanPreviousOutput()
137 ->initializeOutputCompression()
138 ->sendHttpHeaders();
139 }
140
141 /**
142 * Creates a response object with JSON headers automatically, and then dispatches to the correct route
143 *
144 * @param ServerRequestInterface $request
145 * @return ResponseInterface $response
146 * @throws ResourceNotFoundException if no valid route was found
147 * @throws InvalidRequestTokenException if the request could not be verified
148 */
149 protected function dispatch(ServerRequestInterface $request)
150 {
151 /** @var Response $response */
152 $response = GeneralUtility::makeInstance(Response::class, 'php://temp', 200, [
153 'Content-Type' => 'application/json; charset=utf-8',
154 'X-JSON' => 'true'
155 ]);
156
157 /** @var RouteDispatcher $dispatcher */
158 $dispatcher = GeneralUtility::makeInstance(RouteDispatcher::class);
159 return $dispatcher->dispatch($request, $response);
160 }
161 }