Feature: #83725 - Support for PSR-15 HTTP middlewares

See forge#83725

Description

Support for PSR-15 style HTTP middlewares has been added for frontend and backend requests.

PSR-15 style middlewares are intended to be used to move common request and response processing away from the application layer into (possibly reusable) components. Middlewares are concentric layers surrounding other middlewares (so called inner middlewares) or request handlers; that means they can perform pre- and postprocessing of request and response objects (PSR-7). They allow to enrich or exchange PSR-7 objects in order to add functionality or to perform early returns (without invoking the core application).

Common middleware usecases are layers for authentication, authorization, security enforcement, or the conversion of exceptions (like TYPO3's PageNotFoundException) into HTTP response objects.

Adding PSR-15 to TYPO3 allows to restructure TYPO3's existing PHP classes into smaller chunks, while giving developers the possibility to add own middlewares at a specific position in the middleware chain (via TYPO3's dependency ordering).

Middlewares in TYPO3 are added into middleware stacks; not every middleware needs to be called for every HTTP request. Currently TYPO3 supports a generic "frontend" and a "backend" stack; they're run for any TYPO3 Frontend or TYPO3 Backend request respectively. These stacks are processed before the actual Request Handler (which implements the PSR-15 RequestHandlerInterface) handles the application logic. The Request Handler produces a PSR-7 Response object which is propagated back through all middlewares of the stack.

Impact

To add a middleware to the "frontend" or "backend" middleware stack, create the Configuration/RequestMiddlewares.php in the respective extension:

return [
    // stack name: currently 'frontend' or 'backend'
    'frontend' => [
        'middleware-identifier' => [
            'target' => \ACME\Ext\Middleware::class,
            'description' => '',
            'before' => [
                'another-middleware-identifier',
            ],
            'after' => [
                'yet-another-middleware-identifier',
            ],
        ]
    ]
];

If extensions need to shut down or substitute existing middlewares with an own solution, they can disable an existing middleware by adding the following code in Configuration/RequestMiddlewares.php: of their extension.

return [
    'frontend' => [
        'middleware-identifier' => [
            'disabled' => true,
        ],
    ],
];