Skip to content

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

@edsrzf

Description

@edsrzf

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

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy