[FEATURE] Allow deactivation of PSR-15 middlewares 25/55725/5
authorChristian Kuhn <lolli@schwarzbu.ch>
Thu, 15 Feb 2018 01:20:19 +0000 (02:20 +0100)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sat, 17 Feb 2018 20:07:27 +0000 (21:07 +0100)
Similar to other places that use dependency configurations
via arrays, the middleware stack configuration now allows
disabling single middlewares by setting disabled=true.

Change-Id: I42c741062b5f6952577e164939593f0553b1ad31
Resolves: #83907
Related: #83906
Related: #83725
Releases: master
Reviewed-on: https://review.typo3.org/55725
Reviewed-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: Mathias Schreiber <mathias.schreiber@typo3.com>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Benjamin Franzke <bfr@qbus.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/core/Classes/Http/MiddlewareStackResolver.php
typo3/sysext/core/Classes/Http/NormalizedParams.php
typo3/sysext/core/Documentation/Changelog/master/Feature-83725-SupportForPSR-15HTTPMiddlewares.rst
typo3/sysext/core/Tests/Unit/Http/Fixtures/Package1/Configuration/RequestMiddlewares.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Http/Fixtures/Package2/Configuration/RequestMiddlewares.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Http/Fixtures/Package2Disables1/Configuration/RequestMiddlewares.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Http/MiddlewareStackResolverTest.php [new file with mode: 0644]

index 68856be..4d4b039 100644 (file)
@@ -118,6 +118,10 @@ class MiddlewareStackResolver
 
             $sanitizedMiddlewares = [];
             foreach ($middlewaresOfStack as $name => $middleware) {
+                if (isset($middleware['disabled']) && $middleware['disabled'] === true) {
+                    // Skip this middleware if disabled by configuration
+                    continue;
+                }
                 $sanitizedMiddlewares[$name] = $middleware['target'];
             }
 
index 6731d67..008da9f 100644 (file)
@@ -21,7 +21,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
 /**
  * This class provides normalized server parameters in HTTP request context.
  * It normalizes reverse proxy scenarios and various other web server specific differences
- * of native the PSR-7 request object parameters (->getServerParams() / $GLOBALS['_SERVER']).
+ * of the native PSR-7 request object parameters (->getServerParams() / $GLOBALS['_SERVER']).
  *
  * An instance of this class is available as PSR-7 ServerRequestInterface attribute:
  * $normalizedParams = $request->getAttribute('normalizedParams')
index 207178d..80f1ce7 100644 (file)
@@ -37,21 +37,34 @@ To add a middleware to the "frontend" or "backend" middleware stack, create the
 
 .. code-block:: php
 
-       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',
-                               ],
-                       ]
-               ]
-       ];
-
-
-.. index:: Backend, Frontend, PHP-API, NotScanned
+    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 :file:`Configuration/RequestMiddlewares.php`: of their
+extension.
+
+.. code-block:: php
+
+    return [
+        'frontend' => [
+            'middleware-identifier' => [
+                'disabled' => true,
+            ],
+        ],
+    ];
+
+.. index:: Backend, Frontend, PHP-API
diff --git a/typo3/sysext/core/Tests/Unit/Http/Fixtures/Package1/Configuration/RequestMiddlewares.php b/typo3/sysext/core/Tests/Unit/Http/Fixtures/Package1/Configuration/RequestMiddlewares.php
new file mode 100644 (file)
index 0000000..e433021
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+return [
+    'testStack' => [
+        'firstMiddleware' => [
+            'target' => 'aClassName',
+        ],
+    ]
+];
diff --git a/typo3/sysext/core/Tests/Unit/Http/Fixtures/Package2/Configuration/RequestMiddlewares.php b/typo3/sysext/core/Tests/Unit/Http/Fixtures/Package2/Configuration/RequestMiddlewares.php
new file mode 100644 (file)
index 0000000..6ebc2c9
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+return [
+    'testStack' => [
+        'secondMiddleware' => [
+            'target' => 'anotherClassName',
+        ],
+    ]
+];
diff --git a/typo3/sysext/core/Tests/Unit/Http/Fixtures/Package2Disables1/Configuration/RequestMiddlewares.php b/typo3/sysext/core/Tests/Unit/Http/Fixtures/Package2Disables1/Configuration/RequestMiddlewares.php
new file mode 100644 (file)
index 0000000..a284dd5
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+return [
+    'testStack' => [
+        'firstMiddleware' => [
+            'disabled' => true,
+        ],
+        'secondMiddleware' => [
+            'target' => 'anotherClassName',
+        ],
+    ]
+];
diff --git a/typo3/sysext/core/Tests/Unit/Http/MiddlewareStackResolverTest.php b/typo3/sysext/core/Tests/Unit/Http/MiddlewareStackResolverTest.php
new file mode 100644 (file)
index 0000000..5074711
--- /dev/null
@@ -0,0 +1,88 @@
+<?php
+declare(strict_types = 1);
+namespace TYPO3\CMS\Core\Tests\Unit\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 Prophecy\Argument;
+use TYPO3\CMS\Core\Cache\Frontend\PhpFrontend;
+use TYPO3\CMS\Core\Http\MiddlewareStackResolver;
+use TYPO3\CMS\Core\Package\Package;
+use TYPO3\CMS\Core\Package\PackageManager;
+use TYPO3\CMS\Core\Service\DependencyOrderingService;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+/**
+ * Test case
+ */
+class MiddlewareStackResolverTest extends UnitTestCase
+{
+    /**
+     * @test
+     */
+    public function resolveReturnsMiddlewareStack()
+    {
+        $package1 = $this->prophesize(Package::class);
+        $package1->getPackagePath()->willReturn(__DIR__ . '/' . 'Fixtures/Package1/');
+        $package2 = $this->prophesize(Package::class);
+        $package2->getPackagePath()->willReturn(__DIR__ . '/' . 'Fixtures/Package2/');
+        $packageManagerProphecy = $this->prophesize(PackageManager::class);
+        $packageManagerProphecy->getActivePackages()->willReturn([$package1->reveal(), $package2->reveal()]);
+        $dependencyOrderingServiceProphecy = $this->prophesize(DependencyOrderingService::class);
+        $dependencyOrderingServiceProphecy->orderByDependencies(Argument::cetera())->willReturnArgument(0);
+        $phpFrontendCacheProphecy = $this->prophesize(PhpFrontend::class);
+        $phpFrontendCacheProphecy->has(Argument::cetera())->willReturn(false);
+        $phpFrontendCacheProphecy->set(Argument::cetera())->willReturn(false);
+
+        $subject = new MiddlewareStackResolver(
+            $packageManagerProphecy->reveal(),
+            $dependencyOrderingServiceProphecy->reveal(),
+            $phpFrontendCacheProphecy->reveal()
+        );
+        $expected = [
+            'secondMiddleware' => 'anotherClassName',
+            'firstMiddleware' => 'aClassName',
+        ];
+        $this->assertEquals($expected, $subject->resolve('testStack'));
+    }
+
+    /**
+     * @test
+     */
+    public function resolveAllowsDisablingAMiddleware()
+    {
+        $package1 = $this->prophesize(Package::class);
+        $package1->getPackagePath()->willReturn(__DIR__ . '/' . 'Fixtures/Package1/');
+        $package2 = $this->prophesize(Package::class);
+        $package2->getPackagePath()->willReturn(__DIR__ . '/' . 'Fixtures/Package2Disables1/');
+        $packageManagerProphecy = $this->prophesize(PackageManager::class);
+        $packageManagerProphecy->getActivePackages()->willReturn([$package1->reveal(), $package2->reveal()]);
+        $dependencyOrderingServiceProphecy = $this->prophesize(DependencyOrderingService::class);
+        $dependencyOrderingServiceProphecy->orderByDependencies(Argument::cetera())->willReturnArgument(0);
+        $phpFrontendCacheProphecy = $this->prophesize(PhpFrontend::class);
+        $phpFrontendCacheProphecy->has(Argument::cetera())->willReturn(false);
+        $phpFrontendCacheProphecy->set(Argument::cetera())->willReturn(false);
+
+        $subject = new MiddlewareStackResolver(
+            $packageManagerProphecy->reveal(),
+            $dependencyOrderingServiceProphecy->reveal(),
+            $phpFrontendCacheProphecy->reveal()
+        );
+        $expected = [
+            // firstMiddleware is missing, RequestMiddlewares.php of Package2 sets disables=true on firstMiddleware
+            'secondMiddleware' => 'anotherClassName',
+        ];
+        $this->assertEquals($expected, $subject->resolve('testStack'));
+    }
+}