Skip to content

Instantly share code, notes, and snippets.

@jberger
Last active September 18, 2016 05:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jberger/800fe7923f5cb48f39d3f1f9cde96e00 to your computer and use it in GitHub Desktop.
Save jberger/800fe7923f5cb48f39d3f1f9cde96e00 to your computer and use it in GitHub Desktop.

Sorry no one answered this yet. I used to try to keep a closer eye on stack overflow but I got lazy :-P. This is a very interesting question.

Standard redirects (301/302) use the same verb as the original request UNLESS the original request was a POST Interestingly, this behavior was not really intended. A redirect is supposed to use the same request method as the original, but the POST->GET redirect is so commonly intended that most browsers added this behavior even though it was against the original definition. However some people really wanted a POST to remain a POST and now it depended on the implementation. In fact this got so bad that HTTP added response statuses 307/308 which always redirects as the same http verb (ie POST -> POST), even thought that was already the official behavior of the old ones but that ship had sailed. This means that POST->GET, but DELETE->DELETE is the defacto behavior of the 301/302.

This can be demonstrated in the following one liner ($_ in these one-liners is the controller):

perl -Mojo -E 'del "/delete" => sub { $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete

DELETE /delete HTTP/1.1
Host: 127.0.0.1:62690
Accept-Encoding: gzip
User-Agent: Mojolicious (Perl)
Content-Length: 0

HTTP/1.1 302 Found
Date: Sun, 18 Sep 2016 03:25:58 GMT
Server: Mojolicious (Perl)
Location: /
Content-Length: 0

DELETE / HTTP/1.1
Content-Length: 0
User-Agent: Mojolicious (Perl)
Host: 127.0.0.1:62690
Accept-Encoding: gzip

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 5
Date: Sun, 18 Sep 2016 03:25:58 GMT
Server: Mojolicious (Perl)

I got a DELETE

You can see that since my / route handles all methods we get a response, however the request was a DELETE. I see that in your app, you redirect to another named route whose url also handles DELETE. This is a source of your confusion as you are actually ending up there in your tests. Your redirect is effectively DELETE /backups/<<id>> -> DELETE /backups, if I'm reading your code correctly.

Now as opposed to the people who wanted to keep POST as POST, what you want here is the opposite, you want to redirect from DELETE to GET because you are trying to show a response that is not the original resource. This is the defined behavior of the little-known 303 response in which any request method is redirected to a GET. Indeed this is what early browsers should have insisted on rather than breaking the 302.

In the following example I modify the response code to 303 explicitly.

$ perl -Mojo -E 'del "/delete" => sub { $_->res->code(303); $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
DELETE /delete HTTP/1.1
User-Agent: Mojolicious (Perl)
Host: 127.0.0.1:62716
Accept-Encoding: gzip
Content-Length: 0

HTTP/1.1 303 See Other
Location: /
Content-Length: 0
Server: Mojolicious (Perl)
Date: Sun, 18 Sep 2016 03:27:19 GMT

DELETE / HTTP/1.1
User-Agent: Mojolicious (Perl)
Accept-Encoding: gzip
Content-Length: 0
Host: 127.0.0.1:62716

HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Server: Mojolicious (Perl)
Content-Length: 5
Date: Sun, 18 Sep 2016 03:27:19 GMT

I got a DELETE

But whoops, that's still a DELETE! That's because there was a bug in Mojo::UserAgent so that it didn't handle 303s correctly. I'd suggest you still make the change to your code since browsers seem to handle 303s correctly. However since Mojo::UserAgent powers Test::Mojo, your tests can't test that behavior yet. Once fixed you will see it work correctly, as my example does in my local branch:

$ perl -Ilib -Mojo -E 'del "/delete" => sub { $_->res->code(303); $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
DELETE /delete HTTP/1.1                                                                  
Content-Length: 0                                                                        
User-Agent: Mojolicious (Perl)                                                           
Host: 127.0.0.1:64924                                                                    
Accept-Encoding: gzip                                                                    

HTTP/1.1 303 See Other                                                                   
Date: Sun, 18 Sep 2016 04:59:37 GMT                                                      
Location: /                                                                              
Server: Mojolicious (Perl)                                                               
Content-Length: 0                                                                        

GET / HTTP/1.1                                                                           
Content-Length: 0                                                                        
User-Agent: Mojolicious (Perl)                                                           
Host: 127.0.0.1:64924                                                                    
Accept-Encoding: gzip                                                                    

HTTP/1.1 200 OK                                                                          
Date: Sun, 18 Sep 2016 04:59:37 GMT                                                      
Content-Type: text/html;charset=UTF-8                                                    
Server: Mojolicious (Perl)                                                               
Content-Length: 12                                                                       

I got a GET

To see more about redirect response types see https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection

@jberger
Copy link
Author

jberger commented Sep 18, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment