From ff39f5b08da2031666dab8c3b850a8f999cccb0c Mon Sep 17 00:00:00 2001 From: Aleksey Polyvanyi Date: Thu, 14 Nov 2024 13:50:51 +0100 Subject: [PATCH 1/3] fix(state): do not check content type if no input --- .../Provider/ContentNegotiationProvider.php | 12 ++-- .../ContentNegotiationProviderTest.php | 62 +++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/State/Provider/ContentNegotiationProvider.php b/src/State/Provider/ContentNegotiationProvider.php index 0ffd42607b6..d1ed4a0b9c9 100644 --- a/src/State/Provider/ContentNegotiationProvider.php +++ b/src/State/Provider/ContentNegotiationProvider.php @@ -108,14 +108,14 @@ private function getInputFormat(HttpOperation $operation, Request $request): ?st return $format; } - $supportedMimeTypes = []; - foreach ($formats as $mimeTypes) { - foreach ($mimeTypes as $mimeType) { - $supportedMimeTypes[] = $mimeType; + if ($operation->canDeserialize() === true && !$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) { + $supportedMimeTypes = []; + foreach ($formats as $mimeTypes) { + foreach ($mimeTypes as $mimeType) { + $supportedMimeTypes[] = $mimeType; + } } - } - if (!$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) { throw new UnsupportedMediaTypeHttpException(\sprintf('The content-type "%s" is not supported. Supported MIME types are "%s".', $contentType, implode('", "', $supportedMimeTypes))); } diff --git a/tests/State/Provider/ContentNegotiationProviderTest.php b/tests/State/Provider/ContentNegotiationProviderTest.php index e4eb99ba904..2652a8320cb 100644 --- a/tests/State/Provider/ContentNegotiationProviderTest.php +++ b/tests/State/Provider/ContentNegotiationProviderTest.php @@ -21,6 +21,7 @@ use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException; class ContentNegotiationProviderTest extends TestCase { @@ -60,4 +61,65 @@ public function testRequestWithEmptyContentType(): void $this->assertSame($expectedResult, $result); } + + public function testRequestWhenNoInput(): void + { + $expectedResult = new \stdClass(); + + $decorated = $this->prophesize(ProviderInterface::class); + $decorated->provide(Argument::cetera())->willReturn($expectedResult); + + $negotiator = new Negotiator(); + $formats = ['jsonld' => ['application/ld+json']]; + $errorFormats = ['jsonld' => ['application/ld+json']]; + + $provider = new ContentNegotiationProvider($decorated->reveal(), $negotiator, $formats, $errorFormats); + + $request = new Request( + server: [ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/', + 'CONTENT_TYPE' => 'some-not-supported/content-type', + ], + content: '' + ); + + $operation = new Post(); + $operation = $operation->withDeserialize(false); + $context = ['request' => $request]; + + $result = $provider->provide($operation, [], $context); + + $this->assertSame($expectedResult, $result); + } + + public function testRequestWithInput(): void + { + $this->expectException(UnsupportedMediaTypeHttpException::class); + + $decorated = $this->prophesize(ProviderInterface::class); + + $negotiator = new Negotiator(); + $formats = ['jsonld' => ['application/ld+json']]; + $errorFormats = ['jsonld' => ['application/ld+json']]; + + $provider = new ContentNegotiationProvider($decorated->reveal(), $negotiator, $formats, $errorFormats); + + $request = new Request( + server: [ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/', + 'CONTENT_TYPE' => 'some-not-supported/content-type', + ], + content: '' + ); + + $operation = new Post(); + $operation = $operation->withDeserialize(); + $context = ['request' => $request]; + + $result = $provider->provide($operation, [], $context); + + $this->assertSame($expectedResult, $result); + } } From dcf2ad95e6c5ca7d4b275ac29a172cb96a42af93 Mon Sep 17 00:00:00 2001 From: Aleksey Polyvanyi Date: Thu, 14 Nov 2024 14:51:01 +0100 Subject: [PATCH 2/3] -refactoring --- src/State/Provider/ContentNegotiationProvider.php | 2 +- tests/State/Provider/ContentNegotiationProviderTest.php | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/State/Provider/ContentNegotiationProvider.php b/src/State/Provider/ContentNegotiationProvider.php index d1ed4a0b9c9..0179e6c589b 100644 --- a/src/State/Provider/ContentNegotiationProvider.php +++ b/src/State/Provider/ContentNegotiationProvider.php @@ -108,7 +108,7 @@ private function getInputFormat(HttpOperation $operation, Request $request): ?st return $format; } - if ($operation->canDeserialize() === true && !$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) { + if (false !== $operation->canDeserialize() && !$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) { $supportedMimeTypes = []; foreach ($formats as $mimeTypes) { foreach ($mimeTypes as $mimeType) { diff --git a/tests/State/Provider/ContentNegotiationProviderTest.php b/tests/State/Provider/ContentNegotiationProviderTest.php index 2652a8320cb..dd610bd4b8d 100644 --- a/tests/State/Provider/ContentNegotiationProviderTest.php +++ b/tests/State/Provider/ContentNegotiationProviderTest.php @@ -118,8 +118,6 @@ public function testRequestWithInput(): void $operation = $operation->withDeserialize(); $context = ['request' => $request]; - $result = $provider->provide($operation, [], $context); - - $this->assertSame($expectedResult, $result); + $provider->provide($operation, [], $context); } } From 3cfc3ce63c27c47667bd9ff320153c479d515aaf Mon Sep 17 00:00:00 2001 From: Aleksey Polyvanyi Date: Thu, 14 Nov 2024 16:35:20 +0100 Subject: [PATCH 3/3] -refactoring --- src/State/Provider/ContentNegotiationProvider.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/State/Provider/ContentNegotiationProvider.php b/src/State/Provider/ContentNegotiationProvider.php index 0179e6c589b..d9f242ce85e 100644 --- a/src/State/Provider/ContentNegotiationProvider.php +++ b/src/State/Provider/ContentNegotiationProvider.php @@ -97,6 +97,14 @@ private function flattenMimeTypes(array $formats): array */ private function getInputFormat(HttpOperation $operation, Request $request): ?string { + if ( + false === ($input = $operation->getInput()) + || (\is_array($input) && null === $input['class']) + || false === $operation->canDeserialize() + ) { + return null; + } + $contentType = $request->headers->get('CONTENT_TYPE'); if (null === $contentType || '' === $contentType) { return null; @@ -108,7 +116,7 @@ private function getInputFormat(HttpOperation $operation, Request $request): ?st return $format; } - if (false !== $operation->canDeserialize() && !$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) { + if (!$request->isMethodSafe() && 'DELETE' !== $request->getMethod()) { $supportedMimeTypes = []; foreach ($formats as $mimeTypes) { foreach ($mimeTypes as $mimeType) {