From 46e9bcbeb15e81125851505e968783abf36db8ed Mon Sep 17 00:00:00 2001 From: Aleksey Polyvanyi Date: Thu, 14 Nov 2024 13:50:51 +0100 Subject: [PATCH] fix(state): allow application/x-www-form-urlencoded content-type when no input --- .../Provider/ContentNegotiationProvider.php | 12 +++---- .../ContentNegotiationProviderTest.php | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/State/Provider/ContentNegotiationProvider.php b/src/State/Provider/ContentNegotiationProvider.php index 0ffd42607b6..0e2601bc9d1 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() && !$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..71f3e2ef004 100644 --- a/tests/State/Provider/ContentNegotiationProviderTest.php +++ b/tests/State/Provider/ContentNegotiationProviderTest.php @@ -60,4 +60,40 @@ public function testRequestWithEmptyContentType(): void $this->assertSame($expectedResult, $result); } + + public function testRequestWithApplicationXWwwFormUrlencodedContentType(): 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); + + // in Symfony (at least up to 7.0.2, 6.4.2, 6.3.11, 5.4.34), a request + // without a content-type and content-length header will result in the + // variables set to an empty string, not null + + $request = new Request( + server: [ + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/', + 'CONTENT_TYPE' => '', + 'CONTENT_LENGTH' => '', + 'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded', + ], + content: '' + ); + + $operation = new Post(); + $context = ['request' => $request]; + + $result = $provider->provide($operation, [], $context); + + $this->assertSame($expectedResult, $result); + } }