2 declare(strict_types
= 1);
3 namespace TYPO3\CMS\Core\Tests\Unit\Http
;
6 * This file is part of the TYPO3 CMS project.
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
15 * The TYPO3 project - inspiring people to share!
18 use Psr\Http\Message\ResponseInterface
;
19 use Psr\Http\Message\ServerRequestInterface
;
20 use Psr\Http\Server\MiddlewareInterface
;
21 use Psr\Http\Server\RequestHandlerInterface
;
22 use TYPO3\CMS\Core\Http\MiddlewareDispatcher
;
23 use TYPO3\CMS\Core\Http\Response
;
24 use TYPO3\CMS\Core\Http\ServerRequest
;
25 use TYPO3\CMS\Core\Tests\Unit\Http\Fixtures\MiddlewareFixture
;
30 class MiddlewareDispatcherTest
extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
35 public function executesKernelWithEmptyMiddlewareStack()
37 $kernel = new class implements RequestHandlerInterface
{
38 public function handle(ServerRequestInterface
$request): ResponseInterface
40 return (new Response
)->withStatus(204);
44 $dispatcher = new MiddlewareDispatcher($kernel);
45 $response = $dispatcher->handle(new ServerRequest
);
47 $this->assertSame(204, $response->getStatusCode());
53 public function executesMiddlewaresLastInFirstOut()
55 $kernel = new class implements RequestHandlerInterface
{
56 public function handle(ServerRequestInterface
$request): ResponseInterface
60 ->withHeader('X-SEQ-PRE-REQ-HANDLER', $request->getHeader('X-SEQ-PRE-REQ-HANDLER'));
64 $middleware1 = new class implements MiddlewareInterface
{
67 public function process(ServerRequestInterface
$request, RequestHandlerInterface
$handler): ResponseInterface
69 $request = $request->withAddedHeader('X-SEQ-PRE-REQ-HANDLER', $this->id
);
70 $response = $handler->handle($request);
72 return $response->withAddedHeader('X-SEQ-POST-REQ-HANDLER', $this->id
);
76 $middleware2 = clone $middleware1;
77 $middleware2->id
= '1';
79 MiddlewareFixture
::$id = '2';
81 $middleware4 = clone $middleware1;
82 $middleware4->id
= '3';
84 $dispatcher = new MiddlewareDispatcher($kernel, [$middleware1, $middleware2]);
85 $dispatcher->lazy(MiddlewareFixture
::class);
86 $dispatcher->add($middleware4);
88 $response = $dispatcher->handle(new ServerRequest
);
90 $this->assertSame(['3', '2', '1', '0'], $response->getHeader('X-SEQ-PRE-REQ-HANDLER'));
91 $this->assertSame(['0', '1', '2', '3'], $response->getHeader('X-SEQ-POST-REQ-HANDLER'));
92 $this->assertSame(204, $response->getStatusCode());
98 public function doesNotInstantiateLazyMiddlewareInCaseOfAnEarlyReturningOuterMiddleware()
100 $kernel = new class implements RequestHandlerInterface
{
101 public function handle(ServerRequestInterface
$request): ResponseInterface
106 $middleware = new class implements MiddlewareInterface
{
107 public function process(ServerRequestInterface
$request, RequestHandlerInterface
$handler): ResponseInterface
109 return (new Response
)->withStatus(404);
113 MiddlewareFixture
::$hasBeenInstantiated = false;
114 $dispatcher = new MiddlewareDispatcher($kernel, [MiddlewareFixture
::class, $middleware]);
115 $response = $dispatcher->handle(new ServerRequest
);
117 $this->assertFalse(MiddlewareFixture
::$hasBeenInstantiated);
118 $this->assertSame(404, $response->getStatusCode());
124 public function throwsExceptionForLazyNonMiddlewareInterfaceClasses()
126 $this->expectException(\InvalidArgumentException
::class);
127 $this->expectExceptionCode(1516821342);
129 $kernel = new class implements RequestHandlerInterface
{
130 public function handle(ServerRequestInterface
$request): ResponseInterface
136 MiddlewareFixture
::$hasBeenInstantiated = false;
137 $dispatcher = new MiddlewareDispatcher($kernel);
138 $dispatcher->lazy(\stdClass
::class);
139 $response = $dispatcher->handle(new ServerRequest
);
145 public function canBeExcutedMultipleTimes()
147 $kernel = new class implements RequestHandlerInterface
{
148 public function handle(ServerRequestInterface
$request): ResponseInterface
153 $middleware = new class implements MiddlewareInterface
{
154 public function process(ServerRequestInterface
$request, RequestHandlerInterface
$handler): ResponseInterface
156 return (new Response
)->withStatus(204);
160 $dispatcher = new MiddlewareDispatcher($kernel);
161 $dispatcher->add($middleware);
163 $response1 = $dispatcher->handle(new ServerRequest
);
164 $response2 = $dispatcher->handle(new ServerRequest
);
166 $this->assertSame(204, $response1->getStatusCode());
167 $this->assertSame(204, $response2->getStatusCode());
173 public function canBeReExecutedRecursivelyDuringDispatch()
175 $kernel = new class implements RequestHandlerInterface
{
176 public function handle(ServerRequestInterface
$request): ResponseInterface
182 $dispatcher = new MiddlewareDispatcher($kernel);
184 $dispatcher->add(new class($dispatcher) implements MiddlewareInterface
{
185 private $dispatcher = null;
187 public function __construct(RequestHandlerInterface
$dispatcher)
189 $this->dispatcher
= $dispatcher;
192 public function process(ServerRequestInterface
$request, RequestHandlerInterface
$handler): ResponseInterface
194 if ($request->hasHeader('X-NESTED')) {
195 return (new Response
)->withStatus(204)->withAddedHeader('X-TRACE', 'nested');
198 $response = $this->dispatcher
->handle($request->withAddedHeader('X-NESTED', '1'));
200 return $response->withAddedHeader('X-TRACE', 'outer');
204 $response = $dispatcher->handle(new ServerRequest
);
206 $this->assertSame(204, $response->getStatusCode());
207 $this->assertSame(['nested', 'outer'], $response->getHeader('X-TRACE'));