Skip to content

Commit

Permalink
[!!!][TASK] Remove request type specific code in Bootstrap
Browse files Browse the repository at this point in the history
As all request type specific initialization has been
refactored to the Application classes, request type
specific code in Bootstrap is unused [1] and can
be removed.

[1] redirectToInstallTool() is actually still in use, but moved
into the frontend and backend Application classes with this change.
(Also make their parent class abstract as drive-by change.)

Change-Id: Ieded3603c2936d83d3d4701abef6c3884b558e31
Releases: master
Resolves: #83869
Reviewed-on: https://review.typo3.org/55692
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Frank Naegler <frank.naegler@typo3.org>
Tested-by: Frank Naegler <frank.naegler@typo3.org>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
  • Loading branch information
bnf authored and lolli42 committed Feb 28, 2018
1 parent fd28147 commit 2db7744
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 359 deletions.
17 changes: 16 additions & 1 deletion typo3/sysext/backend/Classes/Http/Application.php
Expand Up @@ -14,8 +14,11 @@
*
* The TYPO3 project - inspiring people to share!
*/

use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
use TYPO3\CMS\Core\Http\AbstractApplication;
use TYPO3\CMS\Core\Http\RedirectResponse;

/**
* Entry point for the TYPO3 Backend (HTTP requests)
Expand Down Expand Up @@ -60,7 +63,8 @@ public function __construct($classLoader)

// Redirect to install tool if base configuration is not found
if (!$this->bootstrap->checkIfEssentialConfigurationExists()) {
$this->bootstrap->redirectToInstallTool($this->entryPointLevel);
$this->sendResponse($this->installToolRedirect());
exit;
}

$this->bootstrap->configure();
Expand All @@ -73,4 +77,15 @@ protected function defineLegacyConstants()
{
define('TYPO3_MODE', 'BE');
}

/**
* Create a PSR-7 Response that redirects to the install tool
*
* @return ResponseInterface
*/
protected function installToolRedirect(): ResponseInterface
{
$path = '../' . TYPO3_mainDir . 'install.php';
return new RedirectResponse($path, 302);
}
}
6 changes: 0 additions & 6 deletions typo3/sysext/backend/Configuration/RequestMiddlewares.php
Expand Up @@ -11,14 +11,8 @@
*/
return [
'backend' => [
'typo3/cms-core/legacy-request-handler-dispatcher' => [
'target' => \TYPO3\CMS\Core\Middleware\LegacyRequestHandlerDispatcher::class,
],
'typo3/cms-core/normalized-params-attribute' => [
'target' => \TYPO3\CMS\Core\Middleware\NormalizedParamsAttribute::class,
'after' => [
'typo3/cms-core/legacy-request-handler-dispatcher',
],
],
'typo3/cms-backend/locked-backend' => [
'target' => \TYPO3\CMS\Backend\Middleware\LockedBackendGuard::class,
Expand Down
6 changes: 3 additions & 3 deletions typo3/sysext/core/Classes/Console/CommandRequestHandler.php
Expand Up @@ -64,9 +64,9 @@ public function handleRequest(InputInterface $input)
->loadExtTables()
// create the BE_USER object (not logged in yet)
->initializeBackendUser(CommandLineUserAuthentication::class)
->initializeLanguageObject()
// Make sure output is not buffered, so command-line output and interaction can take place
->endOutputBufferingAndCleanPreviousOutput();
->initializeLanguageObject();
// Make sure output is not buffered, so command-line output and interaction can take place
ob_clean();

$this->populateAvailableCommands();

Expand Down
261 changes: 0 additions & 261 deletions typo3/sysext/core/Classes/Core/Bootstrap.php
Expand Up @@ -18,7 +18,6 @@
use Doctrine\Common\Annotations\AnnotationRegistry;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;

/**
* This class encapsulates bootstrap related methods.
Expand Down Expand Up @@ -57,24 +56,6 @@ class Bootstrap
*/
protected $earlyInstances = [];

/**
* @var string Path to install tool
*/
protected $installToolPath;

/**
* A list of all registered request handlers, see the Application class / entry points for the registration
* @var \TYPO3\CMS\Core\Http\RequestHandlerInterface[]|\TYPO3\CMS\Core\Console\RequestHandlerInterface[]
*/
protected $availableRequestHandlers = [];

/**
* The Response object when using Request/Response logic
* @var \Psr\Http\Message\ResponseInterface
* @see shutdown()
*/
protected $response;

/**
* @var bool
*/
Expand Down Expand Up @@ -266,112 +247,6 @@ public function checkIfEssentialConfigurationExists()
return file_exists($configurationManager->getLocalConfigurationFileLocation()) && file_exists(PATH_typo3conf . 'PackageStates.php');
}

/**
* Redirect to install tool if LocalConfiguration.php is missing.
*
* @param int $entryPointLevel Number of subdirectories where the entry script is located under the document root
* @internal This is not a public API method, do not use in own extensions
*/
public function redirectToInstallTool($entryPointLevel = 0)
{
$path = TYPO3_mainDir . 'install.php';
if ($entryPointLevel > 0) {
$path = str_repeat('../', $entryPointLevel) . $path;
}
header('Location: ' . $path);
die;
}

/**
* Adds available request handlers usually done via an application from the outside.
*
* @param string $requestHandler class which implements the request handler interface
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function registerRequestHandlerImplementation($requestHandler)
{
$this->availableRequestHandlers[] = $requestHandler;
return $this;
}

/**
* Fetches the request handler that suits the best based on the priority and the interface
* Be sure to always have the constants that are defined in $this->defineTypo3RequestTypes() are set,
* so most RequestHandlers can check if they can handle the request.
*
* @param \Psr\Http\Message\ServerRequestInterface|\Symfony\Component\Console\Input\InputInterface $request
* @return \TYPO3\CMS\Core\Http\RequestHandlerInterface|\TYPO3\CMS\Core\Console\RequestHandlerInterface
* @throws \TYPO3\CMS\Core\Exception
* @internal This is not a public API method, do not use in own extensions
*/
public function resolveRequestHandler($request)
{
$suitableRequestHandlers = [];
foreach ($this->availableRequestHandlers as $requestHandlerClassName) {
/** @var \TYPO3\CMS\Core\Http\RequestHandlerInterface|\TYPO3\CMS\Core\Console\RequestHandlerInterface $requestHandler */
$requestHandler = GeneralUtility::makeInstance($requestHandlerClassName, $this);
if ($requestHandler->canHandleRequest($request)) {
$priority = $requestHandler->getPriority();
if (isset($suitableRequestHandlers[$priority])) {
throw new \TYPO3\CMS\Core\Exception('More than one request handler with the same priority can handle the request, but only one handler may be active at a time!', 1176471352);
}
$suitableRequestHandlers[$priority] = $requestHandler;
}
}
if (empty($suitableRequestHandlers)) {
throw new \TYPO3\CMS\Core\Exception('No suitable request handler found.', 1225418233);
}
ksort($suitableRequestHandlers);
return array_pop($suitableRequestHandlers);
}

/**
* Builds a Request instance from the current process, and then resolves the request
* through the request handlers depending on Frontend, Backend, CLI etc.
*
* @param \Psr\Http\Message\RequestInterface|\Symfony\Component\Console\Input\InputInterface $request
* @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)
{
// Resolve request handler that were registered based on the Application
$requestHandler = $this->resolveRequestHandler($request);

// Execute the command which returns a Response object or NULL
$this->response = $requestHandler->handleRequest($request);

return $this;
}

/**
* Outputs content if there is a proper Response object.
*
* @return Bootstrap
*/
protected function sendResponse()
{
if ($this->response instanceof \Psr\Http\Message\ResponseInterface && !($this->response instanceof \TYPO3\CMS\Core\Http\NullResponse)) {
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/' . $this->response->getProtocolVersion() . ' ' . $this->response->getStatusCode() . ' ' . $this->response->getReasonPhrase());
}

foreach ($this->response->getHeaders() as $name => $values) {
header($name . ': ' . implode(', ', $values));
}
}
echo $this->response->getBody()->__toString();
}
return $this;
}

/**
* Registers the instance of the specified object for an early boot stage.
* On finalizing the Object Manager initialization, all those instances will
Expand Down Expand Up @@ -708,74 +583,6 @@ public function unsetReservedGlobalVariables()
return $this;
}

/**
* Check adminOnly configuration variable and redirects
* to an URL in file typo3conf/LOCK_BACKEND or exit the script
*
* @throws \RuntimeException
* @param bool $forceProceeding if this option is set, the bootstrap will proceed even if the user is logged in (usually only needed for special AJAX cases, see AjaxRequestHandler)
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function checkLockedBackendAndRedirectOrDie($forceProceeding = false)
{
if ($GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'] < 0) {
throw new \RuntimeException('TYPO3 Backend locked: Backend and Install Tool are locked for maintenance. [BE][adminOnly] is set to "' . (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'] . '".', 1294586847);
}
if (@is_file(PATH_typo3conf . 'LOCK_BACKEND') && $forceProceeding === false) {
$fileContent = file_get_contents(PATH_typo3conf . 'LOCK_BACKEND');
if ($fileContent) {
header('Location: ' . $fileContent);
} else {
throw new \RuntimeException('TYPO3 Backend locked: Browser backend is locked for maintenance. Remove lock by removing the file "typo3conf/LOCK_BACKEND" or use CLI-scripts.', 1294586848);
}
die;
}
return $this;
}

/**
* Compare client IP with IPmaskList and exit the script run
* if the client is not allowed to access the backend
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
* @throws \RuntimeException
*/
public function checkBackendIpOrDie()
{
if (trim($GLOBALS['TYPO3_CONF_VARS']['BE']['IPmaskList'])) {
if (!GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['BE']['IPmaskList'])) {
throw new \RuntimeException('TYPO3 Backend access denied: The IP address of your client does not match the list of allowed IP addresses.', 1389265900);
}
}
return $this;
}

/**
* Check lockSSL configuration variable and redirect
* to https version of the backend if needed
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
* @throws \RuntimeException
*/
public function checkSslBackendAndRedirectIfNeeded()
{
if ((bool)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL'] && !GeneralUtility::getIndpEnv('TYPO3_SSL')) {
if ((int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSLPort']) {
$sslPortSuffix = ':' . (int)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSLPort'];
} else {
$sslPortSuffix = '';
}
list(, $url) = explode('://', GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . TYPO3_mainDir, 2);
list($server, $address) = explode('/', $url, 2);
header('Location: https://' . $server . $sslPortSuffix . '/' . $address);
die;
}
return $this;
}

/**
* Load $TCA
*
Expand Down Expand Up @@ -930,72 +737,4 @@ public function initializeLanguageObject()
$GLOBALS['LANG']->init($GLOBALS['BE_USER']->uc['lang']);
return $this;
}

/**
* Throw away all output that may have happened during bootstrapping by weird extensions
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function endOutputBufferingAndCleanPreviousOutput()
{
ob_clean();
return $this;
}

/**
* Initialize output compression if configured
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function initializeOutputCompression()
{
if (extension_loaded('zlib') && $GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel']) {
if (MathUtility::canBeInterpretedAsInteger($GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel'])) {
@ini_set('zlib.output_compression_level', (string)$GLOBALS['TYPO3_CONF_VARS']['BE']['compressionLevel']);
}
ob_start('ob_gzhandler');
}
return $this;
}

/**
* Send HTTP headers if configured
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function sendHttpHeaders()
{
array_map('header', $GLOBALS['TYPO3_CONF_VARS']['BE']['HTTP']['Response']['Headers'] ?? []);
return $this;
}

/**
* Things that should be performed to shut down the framework.
* This method is called in all important scripts for a clean
* shut down of the system.
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function shutdown()
{
$this->sendResponse();
return $this;
}

/**
* Provides an instance of "template" for backend-modules to
* work with.
*
* @return Bootstrap
* @internal This is not a public API method, do not use in own extensions
*/
public function initializeBackendTemplate()
{
$GLOBALS['TBE_TEMPLATE'] = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Template\DocumentTemplate::class);
return $this;
}
}
2 changes: 1 addition & 1 deletion typo3/sysext/core/Classes/Http/AbstractApplication.php
Expand Up @@ -24,7 +24,7 @@
/**
* @internal
*/
class AbstractApplication implements ApplicationInterface
abstract class AbstractApplication implements ApplicationInterface
{
/**
* @var string
Expand Down

0 comments on commit 2db7744

Please sign in to comment.