<?php
+declare(strict_types = 1);
namespace TYPO3\CMS\Backend\Http;
/*
*
* The TYPO3 project - inspiring people to share!
*/
-use TYPO3\CMS\Core\Core\ApplicationInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Http\AbstractApplication;
/**
* Entry point for the TYPO3 Backend (HTTP requests)
*/
-class Application implements ApplicationInterface
+class Application extends AbstractApplication
{
/**
+ * @var string
+ */
+ protected $requestHandler = RequestHandler::class;
+
+ /**
+ * @var string
+ */
+ protected $middlewareStack = 'backend';
+
+ /**
* @var Bootstrap
*/
protected $bootstrap;
protected $entryPointLevel = 1;
/**
- * All available request handlers that can handle backend requests (non-CLI)
- * @var array
- */
- protected $availableRequestHandlers = [
- \TYPO3\CMS\Backend\Http\RequestHandler::class
- ];
-
- /**
* Constructor setting up legacy constant and register available Request Handlers
*
* @param \Composer\Autoload\ClassLoader $classLoader an instance of the class loader
$this->bootstrap->redirectToInstallTool($this->entryPointLevel);
}
- foreach ($this->availableRequestHandlers as $requestHandler) {
- $this->bootstrap->registerRequestHandlerImplementation($requestHandler);
- }
-
$this->bootstrap->configure();
}
/**
- * Set up the application and shut it down afterwards
- *
- * @param callable $execute
- */
- public function run(callable $execute = null)
- {
- $this->bootstrap->handleRequest(\TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals(), 'backend');
-
- if ($execute !== null) {
- call_user_func($execute);
- }
-
- $this->bootstrap->shutdown();
- }
-
- /**
* Define constants and variables
*/
protected function defineLegacyConstants()
*/
return [
'backend' => [
+ 'typo3/cms-core/legacy-request-handler-dispatcher' => [
+ 'target' => \TYPO3\CMS\Core\Middleware\LegacyRequestHandlerDispatcher::class,
+ ],
'typo3/cms-backend/locked-backend' => [
'target' => \TYPO3\CMS\Backend\Middleware\LockedBackendGuard::class,
+ 'after' => [
+ 'typo3/cms-core/legacy-request-handler-dispatcher'
+ ],
],
'typo3/cms-backend/https-redirector' => [
'target' => \TYPO3\CMS\Backend\Middleware\ForcedHttpsBackendRedirector::class,
use Symfony\Component\Console\Input\ArgvInput;
use TYPO3\CMS\Core\Core\ApplicationInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Entry point for the TYPO3 Command Line for Commands
protected $entryPointLevel = 4;
/**
- * All available request handlers that can deal with a CLI Request
- * @var array
- */
- protected $availableRequestHandlers = [
- \TYPO3\CMS\Core\Console\CommandRequestHandler::class,
- ];
-
- /**
* Constructor setting up legacy constants and register available Request Handlers
*
* @param \Composer\Autoload\ClassLoader $classLoader an instance of the class loader
->setRequestType(TYPO3_REQUESTTYPE_CLI)
->baseSetup($this->entryPointLevel);
- foreach ($this->availableRequestHandlers as $requestHandler) {
- $this->bootstrap->registerRequestHandlerImplementation($requestHandler);
- }
-
$this->bootstrap->configure();
}
*/
public function run(callable $execute = null)
{
- $this->bootstrap->handleRequest(new ArgvInput());
+ $handler = GeneralUtility::makeInstance(CommandRequestHandler::class, $this->bootstrap);
+ $handler->handleRequest(new ArgvInput());
if ($execute !== null) {
call_user_func($execute);
}
-
- $this->bootstrap->shutdown();
}
/**
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
-use Psr\Http\Message\ServerRequestInterface;
-use Psr\Http\Server\RequestHandlerInterface;
-use TYPO3\CMS\Core\Http\MiddlewareDispatcher;
-use TYPO3\CMS\Core\Http\MiddlewareStackResolver;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
* @throws \TYPO3\CMS\Core\Exception
* @internal This is not a public API method, do not use in own extensions
*/
- protected function resolveRequestHandler($request)
+ public function resolveRequestHandler($request)
{
$suitableRequestHandlers = [];
foreach ($this->availableRequestHandlers as $requestHandlerClassName) {
* through the request handlers depending on Frontend, Backend, CLI etc.
*
* @param \Psr\Http\Message\RequestInterface|\Symfony\Component\Console\Input\InputInterface $request
- * @param string $middlewareStackName the name of the middleware, usually "frontend" or "backend" for TYPO3 applications
* @return Bootstrap
* @throws \TYPO3\CMS\Core\Exception
* @internal This is not a public API method, do not use in own extensions
*/
- public function handleRequest($request, string $middlewareStackName = null)
+ public function handleRequest($request)
{
// Resolve request handler that were registered based on the Application
$requestHandler = $this->resolveRequestHandler($request);
- // The application requested a middleware stack, and the request handler is PSR-15 capable.
- // Fill the middleware dispatcher; enqueue the request handler as kernel for the middleware stack.
- if ($request instanceof ServerRequestInterface && $requestHandler instanceof RequestHandlerInterface && $middlewareStackName !== null) {
- $resolver = new MiddlewareStackResolver(
- $this->getEarlyInstance(\TYPO3\CMS\Core\Package\PackageManager::class),
- GeneralUtility::makeInstance(\TYPO3\CMS\Core\Service\DependencyOrderingService::class),
- $this->getEarlyInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_core')
- );
- $middlewares = $resolver->resolve($middlewareStackName);
-
- $dispatcher = new MiddlewareDispatcher($requestHandler, $middlewares);
- $this->response = $dispatcher->handle($request);
- } else {
- // Execute the command which returns a Response object or NULL
- $this->response = $requestHandler->handleRequest($request);
- }
+ // Execute the command which returns a Response object or NULL
+ $this->response = $requestHandler->handleRequest($request);
return $this;
}
--- /dev/null
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Core\Http;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Core\Core\ApplicationInterface;
+use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * @internal
+ */
+class AbstractApplication implements ApplicationInterface
+{
+ /**
+ * @var string
+ */
+ protected $requestHandler = '';
+
+ /**
+ * @var string
+ */
+ protected $middlewareStack = '';
+
+ /**
+ * @param RequestHandlerInterface $requestHandler
+ * @return MiddlewareDispatcher
+ */
+ protected function createMiddlewareDispatcher(RequestHandlerInterface $requestHandler): MiddlewareDispatcher
+ {
+ $resolver = new MiddlewareStackResolver(
+ GeneralUtility::makeInstance(\TYPO3\CMS\Core\Package\PackageManager::class),
+ GeneralUtility::makeInstance(\TYPO3\CMS\Core\Service\DependencyOrderingService::class),
+ GeneralUtility::makeInstance(\TYPO3\CMS\Core\Cache\CacheManager::class)->getCache('cache_core')
+ );
+ $middlewares = $resolver->resolve($this->middlewareStack);
+
+ return new MiddlewareDispatcher($requestHandler, $middlewares);
+ }
+
+ /**
+ * Outputs content
+ *
+ * @param ResponseInterface $response
+ */
+ protected function sendResponse(ResponseInterface $response)
+ {
+ if ($response instanceof \TYPO3\CMS\Core\Http\NullResponse) {
+ return;
+ }
+
+ if (!headers_sent()) {
+ // If the response code was not changed by legacy code (still is 200)
+ // then allow the PSR-7 response object to explicitly set it.
+ // Otherwise let legacy code take precedence.
+ // This code path can be deprecated once we expose the response object to third party code
+ if (http_response_code() === 200) {
+ header('HTTP/' . $response->getProtocolVersion() . ' ' . $response->getStatusCode() . ' ' . $response->getReasonPhrase());
+ }
+
+ foreach ($response->getHeaders() as $name => $values) {
+ header($name . ': ' . implode(', ', $values));
+ }
+ }
+ echo $response->getBody()->__toString();
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @return ResponseInterface
+ */
+ protected function handle(ServerRequestInterface $request): ResponseInterface
+ {
+ $requestHandler = GeneralUtility::makeInstance($this->requestHandler, Bootstrap::getInstance());
+ $dispatcher = $this->createMiddlewareDispatcher($requestHandler);
+
+ return $dispatcher->handle($request);
+ }
+
+ /**
+ * Set up the application and shut it down afterwards
+ *
+ * @param callable $execute
+ */
+ public function run(callable $execute = null)
+ {
+ $response = $this->handle(\TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals());
+
+ if ($execute !== null) {
+ call_user_func($execute);
+ }
+
+ $this->sendResponse($response);
+ }
+}
--- /dev/null
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Core\Middleware;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\MiddlewareInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Exception;
+use TYPO3\CMS\Core\Http\NullResponse;
+
+/**
+ * Dispatch legacy request handlers; although
+ * Bootstrap::registerRequestHandlerImplementation() was always
+ * marked as internal quite some extensions use that method
+ * to register custom request handlers.
+ *
+ * @internal
+ */
+class LegacyRequestHandlerDispatcher implements MiddlewareInterface
+{
+ protected $bootstrap;
+
+ public function __construct()
+ {
+ $this->bootstrap = Bootstrap::getInstance();
+ }
+
+ /**
+ * @param ServerRequestInterface $request
+ * @param RequestHandlerInterface $handler
+ * @return ResponseInterface
+ */
+ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
+ {
+ $requestHandler = null;
+
+ try {
+ $requestHandler = $this->bootstrap->resolveRequestHandler($request);
+ } catch (Exception $e) {
+ // 'No suitable request handler found.'
+ if ($e->getCode() !== 1225418233) {
+ throw $e;
+ }
+ }
+
+ if ($requestHandler !== null) {
+ // @todo: E_USER_DEPRECATED
+ return $requestHandler->handleRequest($request) ?? new NullResponse();
+ }
+
+ return $handler->handle($request);
+ }
+}
<?php
+declare(strict_types = 1);
namespace TYPO3\CMS\Frontend\Http;
/*
* The TYPO3 project - inspiring people to share!
*/
-use TYPO3\CMS\Core\Core\ApplicationInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Http\AbstractApplication;
/**
* Entry point for the TYPO3 Frontend
*/
-class Application implements ApplicationInterface
+class Application extends AbstractApplication
{
/**
+ * @var string
+ */
+ protected $requestHandler = RequestHandler::class;
+
+ /**
+ * @var string
+ */
+ protected $middlewareStack = 'frontend';
+
+ /**
* @var Bootstrap
*/
protected $bootstrap;
protected $entryPointLevel = 0;
/**
- * All available request handlers that can deal with a Frontend Request
- * @var array
- */
- protected $availableRequestHandlers = [
- \TYPO3\CMS\Frontend\Http\RequestHandler::class,
- ];
-
- /**
* Constructor setting up legacy constant and register available Request Handlers
*
* @param \Composer\Autoload\ClassLoader $classLoader an instance of the class loader
$this->bootstrap->redirectToInstallTool($this->entryPointLevel);
}
- foreach ($this->availableRequestHandlers as $requestHandler) {
- $this->bootstrap->registerRequestHandlerImplementation($requestHandler);
- }
-
$this->bootstrap->configure();
}
/**
- * Starting point
- *
- * @param callable $execute
- */
- public function run(callable $execute = null)
- {
- $this->bootstrap->handleRequest(\TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals(), 'frontend');
-
- if ($execute !== null) {
- call_user_func($execute);
- }
-
- $this->bootstrap->shutdown();
- }
-
- /**
* Define constants and variables
*/
protected function defineLegacyConstants()
*/
return [
'frontend' => [
+ 'typo3/cms-core/legacy-request-handler-dispatcher' => [
+ 'target' => \TYPO3\CMS\Core\Middleware\LegacyRequestHandlerDispatcher::class,
+ ],
'typo3/cms-frontend/timetracker' => [
'target' => \TYPO3\CMS\Frontend\Middleware\TimeTrackerInitialization::class,
+ 'after' => [
+ 'typo3/cms-core/legacy-request-handler-dispatcher'
+ ],
],
'typo3/cms-frontend/preprocessing' => [
'target' => \TYPO3\CMS\Frontend\Middleware\PreprocessRequestHook::class,
*
* The TYPO3 project - inspiring people to share!
*/
+
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Cache\Backend\NullBackend;
-use TYPO3\CMS\Core\Core\ApplicationInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
+use TYPO3\CMS\Core\Http\AbstractApplication;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Entry point for the TYPO3 Install Tool
*/
-class Application implements ApplicationInterface
+class Application extends AbstractApplication
{
/**
* @var Bootstrap
->setRequestType(TYPO3_REQUESTTYPE_INSTALL)
->baseSetup($this->entryPointLevel);
- foreach ($this->availableRequestHandlers as $requestHandler) {
- $this->bootstrap->registerRequestHandlerImplementation($requestHandler);
- }
-
$this->bootstrap
->startOutputBuffering()
->loadConfigurationAndInitialize(false, \TYPO3\CMS\Core\Package\FailsafePackageManager::class);
}
/**
- * Set up the application and shut it down afterwards
- * Failsafe minimal setup mode for the install tool
- * Does not call "run()" therefore
- *
- * @param callable $execute
+ * @param ServerRequestInterface $request
+ * @return ResponseInterface
*/
- public function run(callable $execute = null)
+ protected function handle(ServerRequestInterface $request): ResponseInterface
{
- $this->bootstrap->handleRequest(\TYPO3\CMS\Core\Http\ServerRequestFactory::fromGlobals());
-
- if ($execute !== null) {
- call_user_func($execute);
+ foreach ($this->availableRequestHandlers as $requestHandler) {
+ $handler = GeneralUtility::makeInstance($requestHandler, $this->bootstrap);
+ if ($handler->canHandleRequest($request)) {
+ return $handler->handleRequest($request);
+ }
}
- $this->bootstrap->shutdown();
+ throw new \TYPO3\CMS\Core\Exception('No suitable request handler found.', 1518448686);
}
/**