Skip to content

307 redirect for POST/PUT requests #26171

Closed
@cooldude77

Description

@cooldude77
Q A
Bug report? no
Feature request? yes
BC Break report? unsure
RFC? unsure
Symfony version 2.8.33

I have a version v2 of an API which has majority routes going back to V1, except for a few .
For v2


v2_rest_save_adresses:
    pattern:  api/v2/addresses
    defaults:
        _controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
        route: rest_save_adresses
        permanent: false

For V1


rest_save_adresses:
    pattern:  api/v1/addresses
    defaults: { _controller: XYZRestBundle:Address:create}
    methods: [POST]

The GET requests get redirected with 302 code successfully, while the post requests see an error like this

No route found for "GET /api/v1/addresses": Method Not Allowed (Allow: POST)

The class that does the routing has handling only for parameters 301 and 302.


    /**
     * Redirects to another route with the given name.
     *
     * The response status code is 302 if the permanent parameter is false (default),
     * and 301 if the redirection is permanent.
     *
     * In case the route name is empty, the status code will be 404 when permanent is false
     * and 410 otherwise.
     *
     * @param Request    $request          The request instance
     * @param string     $route            The route name to redirect to
     * @param bool       $permanent        Whether the redirection is permanent
     * @param bool|array $ignoreAttributes Whether to ignore attributes or an array of attributes to ignore
     *
     * @return Response A Response instance
     *
     * @throws HttpException In case the route name is empty
     */
    public function redirectAction(Request $request, $route, $permanent = false, $ignoreAttributes = false)
    {
        if ('' == $route) {
            throw new HttpException($permanent ? 410 : 404);
        }

        $attributes = array();
        if (false === $ignoreAttributes || is_array($ignoreAttributes)) {
            $attributes = $request->attributes->get('_route_params');
            unset($attributes['route'], $attributes['permanent'], $attributes['ignoreAttributes']);
            if ($ignoreAttributes) {
                $attributes = array_diff_key($attributes, array_flip($ignoreAttributes));
            }
        }

        return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $permanent ? 301 : 302);
    }

This is the reason that a request that is post and that should be redirected with 307 status code is not redirected at all, leading to even POST requests getting transferred as GET.

I just changed line return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $permanent ? 301 : 302);

To
return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), 307);

And this works well ( of course not completely correct). I think this needs an enhancement to even allow POST requests to be redirected.

Proposed solution : (Since I have not learned the pull process completely)

    public function redirectAction(Request $request, $route, $permanent = false, $postOrPut = false, $ignoreAttributes = false)
    {
        if ('' == $route) {
            throw new HttpException($permanent ? 410 : 404);
        }

        $attributes = array();
        if (false === $ignoreAttributes || is_array($ignoreAttributes)) {
            $attributes = $request->attributes->get('_route_params');
            unset($attributes['route'], $attributes['permanent'], $attributes['ignoreAttributes']);
            if ($ignoreAttributes) {
                $attributes = array_diff_key($attributes, array_flip($ignoreAttributes));
            }
        }

        if (true == $postOrPut)
            $code = 307;
        else $code = $permanent ? 301 : 302;

        return new RedirectResponse($this->container->get('router')->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $code);
    }

And in routing use this for POST```

v2_rest_save_adresses:
pattern: api/v2/addresses
defaults:
_controller: Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction
route: rest_save_adresses
postOrPut: true

And for GET it is same as before

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions