From 32cd53c01e5d6882a908c92b347154a048ec1390 Mon Sep 17 00:00:00 2001
From: Martin Ficzel <ficzel@sitegeist.de>
Date: Tue, 10 Dec 2024 10:59:43 +0100
Subject: [PATCH] BUGFIX: The CORS middleware will create the response for an
 OPTIONS request without passing the request down through the process chain

Without this change the preflight lead to a 404 as the OPTIONS request could not be routed which yielded a 404 exception.
---
 Classes/Http/CorsHeaderMiddleware.php        | 12 ++++++++++--
 Tests/Unit/Http/CorsHeaderMiddlewareTest.php | 12 ++++++++----
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/Classes/Http/CorsHeaderMiddleware.php b/Classes/Http/CorsHeaderMiddleware.php
index 81467bb..fd4ee99 100644
--- a/Classes/Http/CorsHeaderMiddleware.php
+++ b/Classes/Http/CorsHeaderMiddleware.php
@@ -6,6 +6,7 @@
 
 use Lmc\HttpConstants\Header;
 use Neos\Flow\Annotations as Flow;
+use Psr\Http\Message\ResponseFactoryInterface;
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
 use Psr\Http\Server\MiddlewareInterface;
@@ -14,6 +15,12 @@
 
 class CorsHeaderMiddleware implements MiddlewareInterface
 {
+    /**
+     * @Flow\Inject
+     * @var ResponseFactoryInterface
+     */
+    protected $responseFactory;
+
     /**
      * @Flow\InjectConfiguration("enabled")
      */
@@ -73,15 +80,16 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
         }
 
         $this->initializeConfiguration();
-
-        $response = $handler->handle($request);
         $method = $request->getMethod();
 
         // method type is not options, return early
         if ($method == 'OPTIONS') {
             $this->logger->debug('CORS Component: Preflight request');
+            $response = $this->responseFactory->createResponse();
             return $this->handlePreflight($request, $response);
         }
+
+        $response = $handler->handle($request);
         return $this->handleRequest($request, $response);
     }
 
diff --git a/Tests/Unit/Http/CorsHeaderMiddlewareTest.php b/Tests/Unit/Http/CorsHeaderMiddlewareTest.php
index 8aa7a45..f2aded7 100644
--- a/Tests/Unit/Http/CorsHeaderMiddlewareTest.php
+++ b/Tests/Unit/Http/CorsHeaderMiddlewareTest.php
@@ -65,9 +65,11 @@ public function testMiddlewarePreflightWithConfig(): void
             };
         });
 
-        $this->responseMock->expects($this->exactly(5))->method('withHeader')->willReturnSelf();
+        $this->responseMock->expects($this->never())->method('withHeader');
 
-        $this->middleware->process($this->requestMock, $this->handlerMock);
+        $response = $this->middleware->process($this->requestMock, $this->handlerMock);
+        $this->assertSame(200, $response->getStatusCode());
+        $this->assertSame('GET', $response->getHeaderLine(Header::ACCESS_CONTROL_ALLOW_METHODS));
     }
 
     public function testMiddlewarePreflightWithWildcardConfig(): void
@@ -83,9 +85,11 @@ public function testMiddlewarePreflightWithWildcardConfig(): void
             };
         });
 
-        $this->responseMock->expects($this->exactly(4))->method('withHeader')->willReturnSelf();
+        $this->responseMock->expects($this->never())->method('withHeader');
 
-         $this->middleware->process($this->requestMock, $this->handlerMock);
+        $response = $this->middleware->process($this->requestMock, $this->handlerMock);
+        $this->assertSame(200, $response->getStatusCode());
+        $this->assertSame('GET', $response->getHeaderLine(Header::ACCESS_CONTROL_ALLOW_METHODS));
     }
 
     public function testMiddlewareActualRequestWithConfig(): void