Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[HttpKernel] Inconsistent MapRequestPayload behavior with empty request body and default parameter #57367

Copy link
Copy link
Open
@edsrzf

Description

@edsrzf
Issue body actions

Symfony version(s) affected

7.1.1

Description

When using MapRequestPayload on a parameter with a default value, behavior with an empty request body is inconsistent and depends on the Content-Type header. There are different possibilities:

  • With no Content-Type, UnsupportedMediaTypeHttpException is thrown.
  • With a Content-Type that isn't understood by the Request class (eg image/jpeg), UnsupportedMediaTypeHttpException is thrown.
  • With a Content-Type that is understood by the Request class, the default parameter value is used. This happens regardless of whether the content is serialized data (eg application/json) or not (eg text/plain).

This distinction doesn't make sense to me because it's based on the arbitrary formats that Request understands, not whether or not the content is actually serialized data.

I think behavior should be consistent in all of these cases, whether it means throwing an exception or using the default parameter value. I would personally prefer using the default, but I think you could make the case either way. However throwing an exception in all cases would probably be a BC break.

How to reproduce

I've written these unit tests which fit within RequestPayloadValueResolverTest and demonstrate the inconsistency:

    public static function provideEmptyRequestBody(): iterable
    {
        // The first two throw Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException
        yield 'no content-type' => ['contentType' => ''];
        yield 'jpeg content-type' => ['contentType' => 'image/jpeg'];

        // The rest are fine and pass the test.
        yield 'json content-type' => ['contentType' => 'application/json'];
        yield 'form content-type' => ['contentType' => 'application/x-www-form-urlencoded'];
        yield 'text content-type' => ['contentType' => 'text/plain'];
    }

    /**
     * @dataProvider provideEmptyRequestBody
     */
    public function testEmptyRequestBodyDefaultParameter(?string $contentType): void
    {
        $payload = new RequestPayload(50);
        $serializer = new Serializer([new ObjectNormalizer()]);
        $validator = $this->createMock(ValidatorInterface::class);
        $resolver = new RequestPayloadValueResolver($serializer, $validator);

        $argument = new ArgumentMetadata('empty', RequestPayload::class, false, true, $payload, false, [
            MapRequestPayload::class => new MapRequestPayload(),
        ]);
        $request = Request::create('/', 'POST', server: ['CONTENT_TYPE' => $contentType]);

        $kernel = $this->createMock(HttpKernelInterface::class);
        $arguments = $resolver->resolve($request, $argument);
        $event = new ControllerArgumentsEvent($kernel, function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST);

        $resolver->onKernelControllerArguments($event);

        $this->assertEquals([$payload], $event->getArguments());
    }

Possible Solution

Always use the default parameter value when the request body is empty.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.