Skip to content

Commit 10e5bf8

Browse files
committed
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.
1 parent 8ca6c1b commit 10e5bf8

File tree

2 files changed

+31
-7
lines changed

2 files changed

+31
-7
lines changed

Classes/Http/CorsHeaderMiddleware.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Lmc\HttpConstants\Header;
88
use Neos\Flow\Annotations as Flow;
9+
use Psr\Http\Message\ResponseFactoryInterface;
910
use Psr\Http\Message\ResponseInterface;
1011
use Psr\Http\Message\ServerRequestInterface;
1112
use Psr\Http\Server\MiddlewareInterface;
@@ -14,6 +15,12 @@
1415

1516
class CorsHeaderMiddleware implements MiddlewareInterface
1617
{
18+
/**
19+
* @Flow\Inject
20+
* @var ResponseFactoryInterface
21+
*/
22+
protected $responseFactory;
23+
1724
/**
1825
* @Flow\InjectConfiguration("enabled")
1926
*/
@@ -73,15 +80,16 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
7380
}
7481

7582
$this->initializeConfiguration();
76-
77-
$response = $handler->handle($request);
7883
$method = $request->getMethod();
7984

80-
// method type is not options, return early
81-
if ($method == 'OPTIONS') {
85+
// method type is OPTIONS, return early
86+
if ($method === 'OPTIONS') {
8287
$this->logger->debug('CORS Component: Preflight request');
88+
$response = $this->responseFactory->createResponse();
8389
return $this->handlePreflight($request, $response);
8490
}
91+
92+
$response = $handler->handle($request);
8593
return $this->handleRequest($request, $response);
8694
}
8795

Tests/Unit/Http/CorsHeaderMiddlewareTest.php

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use PHPUnit\Framework\MockObject\Exception;
1111
use PHPUnit\Framework\MockObject\MockObject;
1212
use PHPUnit\Framework\TestCase;
13+
use Psr\Http\Message\ResponseFactoryInterface;
1314
use Psr\Http\Message\ResponseInterface;
1415
use Psr\Http\Message\ServerRequestInterface;
1516
use Psr\Http\Server\RequestHandlerInterface;
@@ -24,6 +25,7 @@ class CorsHeaderMiddlewareTest extends TestCase
2425
private readonly ResponseInterface&MockObject $responseMock;
2526
private readonly RequestHandlerInterface&MockObject $handlerMock;
2627
private readonly LoggerInterface&MockObject $logger;
28+
private readonly ResponseFactoryInterface&MockObject $responseFactoryMock;
2729

2830
/**
2931
* @throws Exception
@@ -35,12 +37,12 @@ protected function setUp(): void
3537
$this->requestMock = $this->createMock(ServerRequestInterface::class);
3638
$this->responseMock = $this->createMock(ResponseInterface::class);
3739
$this->handlerMock = $this->createMock(RequestHandlerInterface::class);
40+
$this->responseFactoryMock = $this->createMock(ResponseFactoryInterface::class);
3841
$this->logger = $this->createMock(LoggerInterface::class);
3942

4043
ObjectAccess::setProperty($this->middleware, 'enabled', true, true);
4144
ObjectAccess::setProperty($this->middleware, 'logger', $this->logger, true);
42-
43-
$this->handlerMock->expects($this->once())->method('handle')->willReturn($this->responseMock);
45+
ObjectAccess::setProperty($this->middleware, 'responseFactory', $this->responseFactoryMock, true);
4446
}
4547

4648
public function testMiddlewareIsNotEnabled(): void
@@ -65,6 +67,9 @@ public function testMiddlewarePreflightWithConfig(): void
6567
};
6668
});
6769

70+
// the process is not passed down the chain and a fresh response is created
71+
$this->handlerMock->expects($this->never())->method('handle');
72+
$this->responseFactoryMock->expects($this->once())->method('createResponse')->willReturn($this->responseMock);
6873
$this->responseMock->expects($this->exactly(5))->method('withHeader')->willReturnSelf();
6974

7075
$this->middleware->process($this->requestMock, $this->handlerMock);
@@ -83,9 +88,12 @@ public function testMiddlewarePreflightWithWildcardConfig(): void
8388
};
8489
});
8590

91+
// the process is not passed down the chain and a fresh response is created
92+
$this->handlerMock->expects($this->never())->method('handle');
93+
$this->responseFactoryMock->expects($this->once())->method('createResponse')->willReturn($this->responseMock);
8694
$this->responseMock->expects($this->exactly(4))->method('withHeader')->willReturnSelf();
8795

88-
$this->middleware->process($this->requestMock, $this->handlerMock);
96+
$this->middleware->process($this->requestMock, $this->handlerMock);
8997
}
9098

9199
public function testMiddlewareActualRequestWithConfig(): void
@@ -100,6 +108,8 @@ public function testMiddlewareActualRequestWithConfig(): void
100108
};
101109
});
102110

111+
// request is passed down the chain
112+
$this->handlerMock->expects($this->once())->method('handle')->willReturn($this->responseMock);
103113
$this->responseMock->expects($this->exactly(4))->method('withHeader')->willReturnSelf();
104114

105115
$this->middleware->process($this->requestMock, $this->handlerMock);
@@ -117,6 +127,8 @@ public function testMiddlewareActualRequestWithWildcardConfig(): void
117127
};
118128
});
119129

130+
// request is passed down the chain
131+
$this->handlerMock->expects($this->once())->method('handle')->willReturn($this->responseMock);
120132
$this->responseMock->expects($this->exactly(4))->method('withHeader')->willReturnSelf();
121133

122134
$this->middleware->process($this->requestMock, $this->handlerMock);
@@ -142,6 +154,8 @@ public function testMiddlewareActualRequestWithWildcardOrigin(): void
142154
};
143155
});
144156

157+
// request is passed down the chain
158+
$this->handlerMock->expects($this->once())->method('handle')->willReturn($this->responseMock);
145159
$this->responseMock->expects($this->exactly(4))->method('withHeader')->willReturnSelf();
146160

147161
$this->middleware->process($this->requestMock, $this->handlerMock);
@@ -167,6 +181,8 @@ public function testMiddlewareActualRequestWithNotAllowedOrigin(): void
167181
};
168182
});
169183

184+
// request is passed down the chain
185+
$this->handlerMock->expects($this->once())->method('handle')->willReturn($this->responseMock);
170186
$this->responseMock->expects($this->never())->method('withHeader')->willReturnSelf();
171187

172188
$this->logger->expects($this->exactly(2))->method('debug');

0 commit comments

Comments
 (0)