restclient.el
restclient.el copied to clipboard
302 redirects
Hi Pasky, love restclient!
Firstly, does restclient handle 302s? I am testing some URL that requires me to login and do a POST but no response whatever. I then perform a separate GET request after the POST login attempt and it shows content for the logined user. Is this the way restclient works? I ask because I am accustomed to how other clients like the Postman works to follow the redirects.
Secondly, I thought it would be good to advertise on the 'frontpage' that we could inhibit restclient from sending cookies implicitly or rather specify explicitly the cookie settings we want. I found out about this only after some searching on the issues list:
# need to firstly turn on [Inhibit restclient from sending cookies implicitly] via M-x customize-variable
GET http://someserver.com Cookie: SESSToken=SESSValue; otherCookieSetting=otherCookieValue
Went here to report this issue, but found this ticket. So I'm just reporting in that this would be nice to see fixed.
I kinda expected it to look like when you use curl -v
to a resource that returns a Location: /whatever
header... which is, just displaying that it got that header back.
I think this is bug of url package, maybe better to use curl :)
See http://git.savannah.gnu.org/cgit/emacs.git/tree/lisp/url/url-http.el#n490 function url-http-parse-headers ()
It not redirect on POST method:
(3 ; Redirection
;; 300 Multiple choices
;; 301 Moved permanently
;; 302 Found
;; 303 See other
;; 304 Not modified
;; 305 Use proxy
;; 307 Temporary redirect
(let ((redirect-uri (or (mail-fetch-field "Location")
(mail-fetch-field "URI"))))
(pcase status-symbol
(`multiple-choices ; 300
;; Quoth the spec (section 10.3.1)
;; -------------------------------
;; The requested resource corresponds to any one of a set of
;; representations, each with its own specific location and
;; agent-driven negotiation information is being provided so
;; that the user can select a preferred representation and
;; redirect its request to that location.
;; [...]
;; If the server has a preferred choice of representation, it
;; SHOULD include the specific URI for that representation in
;; the Location field; user agents MAY use the Location field
;; value for automatic redirection.
;; -------------------------------
;; We do not support agent-driven negotiation, so we just
;; redirect to the preferred URI if one is provided.
nil)
((or `moved-permanently `found `temporary-redirect) ; 301 302 307
;; If the 301|302 status code is received in response to a
;; request other than GET or HEAD, the user agent MUST NOT
;; automatically redirect the request unless it can be
;; confirmed by the user, since this might change the
;; conditions under which the request was issued.
(unless (member url-http-method '("HEAD" "GET"))
;; ---should be POST too ! -------------------^^^^^
(setq redirect-uri nil)))
@osv Okay, first things first. 302 response to POSTs is a gray area. Although it usually works and is widely used, common implementations actually breach HTTP standard. So it's okay for url.el to be a bit stubborn :)
At some point I had automatic 302 handling turned off in restclient.el even for GETs, as I wanted to see what was actually happening, without any extra steps running behind the scenes. I removed this hack later as it became annoyance in my next project, where 302 were used heavily and I had to copy/paste returned locations.
Then there's apparently a bug that makes header parser and highlighter to hang with certain responses, I'm now looking into it. Could you please try and see what do you get with C-c C-r
for this request? Does it hang as well? If not, could you send me exact response you're getting?
@pashky 302 to POSTs might be a gray area. But most references that speaks about how to implement a RESTFul API tells you that you should use POST to create new resources and return 302 to tell the client where the newly created resource is located.
And that PUT is used to update an existing resource. And will therefore not return 302 since you already know the location for this resource.
@etu And your point is? debbugs is that way, I wish you all the best luck explaining modern HTTP there.
In fact, I don't even know what really happens with 302 to POSTs in restclient.el now, I don't have any servers that do this at hand. I'll hack one to test when I have time.
@pashky A restclient should be able to handle common rest usecases. That's my point.
It does nothing. Well, not nothing. The request is sent, but it looks like nothing happened since one doesn't get a response buffer or anything. Not even header information.
Is it same with C-c C-r
?
Yes, both C-c C-c
and C-c C-r
fails, tested with this script:
<?php
trigger_error('Request recived', E_USER_NOTICE);
header('Location: /otherfile.html', true, 302);
With PHP's built in webserver (php -S localhost:8080
).
And in a buffer in emacs with restclient
loaded.
POST http://localhost:8080/
I know the requests works because it prints that in the server-log. But there's no indication within emacs that they work or what happened.
Ok, I see. It's url.el not even calling callback function when such response is enountered and I don't see any easy way to defadvice around this behaviour.
303 works as expected, though. So I'd suggest you to use it instead of 302, it's better and more spec-compliant anyway http://stackoverflow.com/questions/5129076/after-a-post-should-i-do-a-302-or-a-303-redirect
Or my other suggestion to go and fight some windmills at debbugs still on offer too :)
That's hard to do anything about then. At least without patching core stuff I guess.
That works when building your own stuff. I might change my 302 to 303 in POST-cases for the project I almost work on sometimes.
So the issue remains, but the issue is not in restclient
. That means this issue can be closed and we can hope that someone feels like Don Quixote and are up for some windmill fighting. Anyone?
I know the requests works because it prints that in the server-log. But there's no indication within emacs that they work or what happened.
I have used tcpdump to debug! :)
I think while using url
package there no way to fix that behavior. Make restclient depend on external tools like curl
is not good too.
@osv Out of interest, I tried to port restclient to this yesterday. Wasn't that easy, request.el doesn't fit restclient's requirements very well, and has its own limitations, and wasn't updated in 2 years. This one may or may not be better.
Quick overview of request.el. It depend on url package :) I think it not help even it you port
Ran into this one today: 302 redirect to the login page, for a REST POST call behind an apache shiro servlet filter.
The behaviour of restclient.el was to print
Contacting host: lorenzo.hjemme.lan:8181
to the mini-buffer and then stop.
Is there a workaround? Changing from url-http.el to curl was mentioned earlier in this issue. How is that accomplished? Does "curl" mean libcurl linked into emacs? Or does it mean running the curl executable in a separate process?
A good behaviour would be to open the '*HTTP Response*' buffer and show the 302 redirect with headers followed by the new locations with body and headers.
There's no workaround, sorry.
There's one, setting the variable url-max-redirections
to 0 before doing the call will do the trick.
Thanks!
FWIW since 2018 I have learned how to make the REST API return 401 and 403 rather than redirect to login with 302, which makes for a much nicer behaviour.
An example: https://github.com/steinarb/oldalbum/commit/55ee4973c0743165700f5340ae3eca5acc91feb1 https://github.com/steinarb/oldalbum/commit/9f9510e567459637187390ba16aa9016fb8005ce https://github.com/steinarb/oldalbum/commit/feb8a3e9d8125be012b5c76db36e907807f841a7