Skip to content

Use 308 to ensure http method is preserved #9286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 20, 2018

Conversation

greg0ire
Copy link
Contributor

307 and 308 were introduced exactly to solve this issue.

The 307 and 308 status codes were introduced exactly to solve this issue.
@@ -27,7 +27,7 @@ new URL with a 301 response status code::

$url = str_replace($pathInfo, rtrim($pathInfo, ' /'), $requestUri);

return $this->redirect($url, 301);
return $this->redirect($url, 308);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not be 301 if it's a GET method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://httpstatuses.com/308, it works for both GET and POST, and forbids changing them.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Then. But not all people know what 308 code mean. It would be great to add an explanation line with the link you just provided.

@greg0ire
Copy link
Contributor Author

This seems to be fully supported by all browsers: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/308

@soullivaneuh
Copy link
Contributor

soullivaneuh commented Feb 18, 2018

@javiereguiluz @greg0ire As we spoke about doc improvement, I have a question: Why using a controller? Why not a kernel exception listener?

I gave a try and it works very well:

namespace App\Subscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;

final class TrailingSlashSubscriber implements EventSubscriberInterface
{
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return [
            KernelEvents::EXCEPTION => [
                ['onKernelException', 1]
            ]
        ];
    }

    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        if (!$event->getException() instanceof NotFoundHttpException) {
            return;
        }

        $request = $event->getRequest();
        $pathInfo = $request->getPathInfo();
        $requestUri = $request->getRequestUri();

        $url = str_replace($pathInfo, rtrim($pathInfo, '/'), $requestUri);

        if ($url !== $requestUri) {
            $event->setResponse(new RedirectResponse($url, Response::HTTP_PERMANENTLY_REDIRECT));
        }
    }
}

Plus, it avoids possible issue explained by this warning:

Make sure to include this route in your routing configuration at the very end of your route listing. Otherwise, you risk redirecting real routes (including Symfony core routes) that actually do have a trailing slash in their path.

@greg0ire
Copy link
Contributor Author

greg0ire commented Feb 18, 2018

Maybe the controller + route is more explicit than waiting for an exception you could avoid from the start? Otherwise yeah, it looks good too! Anyway, that's the kind of thing I would do even earlier, with my webserver: https://www.scalescale.com/tips/nginx/nginx-remove-trailing-slash/

@soullivaneuh
Copy link
Contributor

@greg0ire That was I was thinking about. But my listener took 1ms to process, so it's still worth it IMO.

@@ -27,7 +27,9 @@ new URL with a 301 response status code::

$url = str_replace($pathInfo, rtrim($pathInfo, ' /'), $requestUri);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related, but we can take benefit to fix it: why a space on rtrim second argument?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because you want to remove spaces too

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? I tried without, works well.

Copy link
Contributor Author

@greg0ire greg0ire Feb 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean what happens if the url is http://my.website/someroute/ <- space here? That works too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@greg0ire Yes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I did it on Chrome, maybe the browser remove it itself? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, because I can't see how that would work

@soullivaneuh
Copy link
Contributor

My listener may also match is the previous excpetion is a ResourceNotFoundException. It will ignores manual not found from controller.

@soullivaneuh
Copy link
Contributor

After some tests, I don't recommend to use a listener.

Indeed, if you try something like /blog/post/4/ where the trailing slash is valid but the post 4 does not exists, it will be redirect to /blog/post/4 and then again to /blog/post/4/.

@javiereguiluz javiereguiluz modified the milestones: 2.2, 2.7 Feb 20, 2018
@javiereguiluz
Copy link
Member

Thanks Grégoire.

@javiereguiluz javiereguiluz merged commit e21cf2f into symfony:2.7 Feb 20, 2018
javiereguiluz added a commit that referenced this pull request Feb 20, 2018
…iereguiluz)

This PR was merged into the 2.7 branch.

Discussion
----------

Use 308 to ensure http method is preserved

307 and 308 were introduced exactly to solve this issue.

Commits
-------

e21cf2f Minor change
f8f6bda Added some minor explanation about 308 code
8549488 Use 308 to ensure http method is preserved
@greg0ire greg0ire deleted the 308_trailing_slash branch February 20, 2018 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants