From e28cef039983dd22a44dbddb21243623fca7084b Mon Sep 17 00:00:00 2001 From: jake johns Date: Tue, 4 Mar 2025 19:05:22 -0500 Subject: [PATCH] Support "Allow" header for 405 errors --- src/ErrorFormatter/AbstractFormatter.php | 18 +++++++++++++++++- tests/ErrorHandlerTest.php | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/ErrorFormatter/AbstractFormatter.php b/src/ErrorFormatter/AbstractFormatter.php index 775e629..1b665a6 100644 --- a/src/ErrorFormatter/AbstractFormatter.php +++ b/src/ErrorFormatter/AbstractFormatter.php @@ -43,7 +43,13 @@ public function handle(Throwable $error, ServerRequestInterface $request): Respo $response = $this->responseFactory->createResponse($this->errorStatus($error)); $body = $this->streamFactory->createStream($this->format($error, $contentType)); - return $response->withBody($body)->withHeader('Content-Type', $contentType); + $response = $response->withBody($body)->withHeader('Content-Type', $contentType); + + if (405 == $response->getStatusCode() && $allow = $this->allow($error)) { + $response = $response->withHeader('Allow', implode(', ', $allow)); + } + + return $response; } protected function errorStatus(Throwable $error): int @@ -59,6 +65,16 @@ protected function errorStatus(Throwable $error): int return 500; } + protected function allow(Throwable $error): ?array + { + if (method_exists($error, 'getContext')) { + $context = $error->getContext(); + return isset($context['allow']) ? (array) $context['allow'] : null; + } + + return null; + } + protected function getContentType(ServerRequestInterface $request): ?string { $accept = $request->getHeaderLine('Accept'); diff --git a/tests/ErrorHandlerTest.php b/tests/ErrorHandlerTest.php index b5421c8..06bd345 100644 --- a/tests/ErrorHandlerTest.php +++ b/tests/ErrorHandlerTest.php @@ -56,6 +56,28 @@ public function getStatusCode(): int $this->assertEquals(418, $response->getStatusCode()); } + public function testNotAllowedException() + { + $response = Dispatcher::run([ + new ErrorHandler(), + function ($request) { + throw new class() extends Exception { + public function getStatusCode(): int + { + return 405; + } + public function getContext(): array + { + return ['allow' => ['GET', 'POST']]; + } + }; + }, + ]); + + $this->assertEquals(405, $response->getStatusCode()); + $this->assertEquals('GET, POST', $response->getHeaderLine('Allow')); + } + public function testGifFormatter() { $request = Factory::createServerRequest('GET', '/');