[!!!][FEATURE] Introduce PSR-7-based Routing for Backend AJAX Requests
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Http / RouteDispatcher.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\Router;
20 use TYPO3\CMS\Backend\Routing\Route;
21 use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
22 use TYPO3\CMS\Core\Http\Dispatcher;
23 use TYPO3\CMS\Core\Http\DispatcherInterface;
24 use TYPO3\CMS\Core\Utility\GeneralUtility;
25 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
26
27 /**
28 * Dispatcher which resolves a route to call a controller and method (but also a callable)
29 */
30 class RouteDispatcher extends Dispatcher implements DispatcherInterface {
31
32 /**
33 * Main method to resolve the route and checks the target of the route, and tries to call it.
34 *
35 * @param ServerRequestInterface $request the current server request
36 * @param ResponseInterface $response the prepared response
37 * @return ResponseInterface the filled response by the callable / controller/action
38 * @throws RouteNotFoundException if the route was not found
39 * @throws \InvalidArgumentException if the defined target for the route is invalid
40 */
41 public function dispatch(ServerRequestInterface $request, ResponseInterface $response) {
42 /** @var Router $router */
43 $router = GeneralUtility::makeInstance(Router::class);
44 /** @var Route $route */
45 $route = $router->matchRequest($request);
46 $request = $request->withAttribute('route', $route);
47 if (!$this->isValidRequest($request)) {
48 throw new RouteNotFoundException('Invalid request for route "' . $route->getPath() . '"', 1425389455);
49 }
50
51 $targetIdentifier = $route->getOption('target');
52 $target = $this->getCallableFromTarget($targetIdentifier);
53 return call_user_func_array($target, array($request, $response));
54 }
55
56 /**
57 * Wrapper method for static form protection utility
58 *
59 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection
60 */
61 protected function getFormProtection() {
62 return FormProtectionFactory::get();
63 }
64
65 /**
66 * Checks if the request token is valid. This is checked to see if the route is really
67 * created by the same instance. Should be called for all routes in the backend except
68 * for the ones that don't require a login.
69 *
70 * @param \Psr\Http\Message\ServerRequestInterface $request
71 * @return bool
72 * @see \TYPO3\CMS\Backend\Routing\UriBuilder where the token is generated.
73 */
74 protected function isValidRequest($request) {
75 $route = $request->getAttribute('route');
76 if ($route->getOption('access') === 'public') {
77 return TRUE;
78 } elseif ($route->getOption('ajax')) {
79 $token = (string)(isset($request->getParsedBody()['ajaxToken']) ? $request->getParsedBody()['ajaxToken'] : $request->getQueryParams()['ajaxToken']);
80 return $this->getFormProtection()->validateToken($token, 'ajaxCall', $route->getOption('_identifier'));
81 } else {
82 $token = (string)(isset($request->getParsedBody()['token']) ? $request->getParsedBody()['token'] : $request->getQueryParams()['token']);
83 return $this->getFormProtection()->validateToken($token, 'route', $route->getOption('_identifier'));
84 }
85 }
86 }