IE9 deletes stuff
techno-weenie.net
techno-weenie.net
Rails happens to function under browsers popular at development time, but what do the standards (see nbpoole's comment) or logic suggest is the correct response for this? Asking the user agent (which in this case essentially means Javascript running on a page the user is browsing) whether /widgets/32 is equivalent to /widgets/ so it should know whether it should nuke it or not? That's a tough question for Javascript and an impossible question for the actual human who is trying to get this year's widget catalog ready.
"User requested a delete, server doesn't say delete is impossible, we'll try deleting until we get back confirmation or get told it is impossible" seems like a fairly sensible decision for me. (It is non-compliant with the specs, but GETing the new URL is also non-compliant with the specs, and that is the non-compliance that Rails relies on to actually function.)
There were similar issues way back in the day back when the Rails community was enamored with redirect_to prior to finding out important constituents on the Internet like, say, Googlebot think there are hugely meaningful differences between 301 redirects and 302 redirects.
respond_to do |format|
format.js { head 200 }
format.xml { head 200 }
format.html { redirect_to '/' }
end
We do something like this in every other case in the code base. This is actually what's more encouraged to Rails developers.There was another similar issue with Rails and the Google Web Accelerator: http://37signals.com/svn/archives2/google_web_accelerator_he.... In this case, the GWA was "clicking" links on the page to pre cache them. Sucks to be you if your application's delete links are straight GET links!
In this situation, the community encountered the problem and immediately started advocating better practices to get around these problems. Such as using form buttons (and later, ajax-enabled links) for unsafe actions. There's a clear standard practice in the web development community here, and these early Rails apps weren't following it.
However, every other browser with XHR support for years has handled redirects the same way. Even though the spec is ambiguous, it certainly suggests being cautious and only automatically redirecting with safe HTTP methods. IE9 breaks this trend for some reason. I'd feel much differently about this if every version of IE worked this way. At least there would be some consistency with itself. And it surely would've been encountered and added to the encyclopedia of weird IE behavior that web developers have to deal with.
redirect_to issues a 302 redirect. According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html, this is what a 302 redirect means:
The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field.
The temporary URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).
If the 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.
Note: RFC 1945 and RFC 2068 specify that the client is not allowed to change the method on the redirected request. However, most existing user agent implementations treat 302 as if it were a 303 response, performing a GET on the Location field-value regardless of the original request method. The status codes 303 and 307 have been added for servers that wish to make unambiguously clear which kind of reaction is expected of the client.
There was another discussion about the use of 302 versus 303 redirects on HN about a month ago: http://news.ycombinator.com/item?id=2791663
Interestingly there was a lot of negativity in that discussion about the author's idea. Criticism was mainly along the lines of "it's too risky" and "it won't work with old browser" along with "the old way works fine, I don't get what the big deal is."
Well, now we have at least one very good reason to pay closer attention to the spec and consider that the use of 303 may be more appropriate.
The discussion was here: http://news.ycombinator.com/item?id=2791663
In there, I commented (http://news.ycombinator.com/item?id=2792357) that I would recommend against 303 because of possibly broken proxies and mainly because browser were already doing the right thing in response to a 302.
How wrong I was as we now have an instance where at least one browser is doing it the way the spec has probably intended for it to be handled.
I would assume they are still handling 302 in response to a POST like every other browser but for 303 they are doing it the way the spec was initially worded.
This is, IMHO, not an IE issue but an IE standards-compliancy-feature at least until somebody here tries whether it works as expected with a 303 status code. If it does and you want it to work differently with a 302 code, then it's probably your turn to get the spec fixed :-)
Something changed with IE9. Maybe jQuery detected it supports DELETE requests? I have no idea.
If the 302 status code is received in response to a request using the POST method, 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.*
http://www.ietf.org/rfc/rfc1945.txt
IE does redirect automatically. So IE isn't doing it right either. Since nobody is doing it right, I'd pick the guys doing it wrong that make the most sense. What a surprise: that's not microsoft.
Regardless, that is a separate issue to what is being discussed, and the article does mention it; I'm sure it's not that it was forgotten. Standards documents aren't always perfect in predicting every possible scenario so there must always be room for practical implementation and I think IE has a very good argument to make in its favor for this specific case.
I think IE has a very good argument to make in its favor for this specific case
Great. What is it?
When sending a request via XHR you can set request headers. Some are standard headers (Content-Type, Accept, etc...), others are not but widely used (X-Requested-With), and others you can make up on the spot. The web server will get those and can act on that to, for instance, customize what will be returned, or do cache work, or whatever.
If the XHR request returns a redirection, browsers will follow it automatically. That's what XHR does. Now most browsers will also re-use the headers you set (minus those for which it makes no sense maybe, not sure about that one actually but I'd expect things like ETag or Last-Modified could be re-set by the browser or stripped off).
Not Firefox. On the other side of the redirection, your new XHR request will not have any of the headers you set. No standard ones (like Accept) and no custom ones (X-Requested-With). All of those will disappear and Firefox will solely send its default sequence of headers. Which definitely are not the ones you want since you bothered customizing that.
> Is there a bug outstanding for this?
Yep: https://bugzilla.mozilla.org/show_bug.cgi?id=553888
it looks like it might be fixed. In Firefox 7.
I've used a hack (I think lifted from django) whereby if you are running firefox and and your request came in with an x-requested-with header and we redirect you, we keep a marker in your session that we just redirected you to url x via xhttp request and store any other custom headers we might have set.
Then when your subsequent request comes in (with all its custom headers including x-requested-with missing) we re-add the headers that were stripped out and route your request based on the infered headers. We only keep this lookup entry around for a very short time (like 30 seconds) and remove it after the first time it is used.
It is a total hack, but it works in most cases. Not using redirects on xmlhttp requests is pretty limiting - it is a real shame that the FF devs took so long to fix this bug as it now exits in tons of installs that will probably be around for years to come.
yeah I had to do that kind of stuff as well.
> Not using redirects on xmlhttp requests is pretty limiting
I don't agree. The reality is that it should not be needed, redirect-after-post (let alone DELETE or PUT) is a workaround for browser UI issues ("Do you want to re-send this POST request" popups on refresh) and URI localization (bookmarkability of the landing page). There are reasons for redirects in xhr scenarios, but they have to do mostly with clients "caching" old URLs and the service changing its URI structure.
There's little to no reason to send a redirect (let alone a temporary one) to an XHR.
My code (I've tried it with both upper-case and lower-case DELETE):
<form action="http://example.com" method="DELETE">
<input type="submit" />
</form>I would reference when it was added, but since it's a working draft spec, it's been removed and I can't find the original addition date - but I believe it to be mid to late 2009.
[1] http://www.w3.org/TR/2010/WD-html5-diff-20101019/#changes-20...
You're writing a standard at the time when you know the least about how and why the thing you spec would be used. You can't get it right (you still can do "mostly right"), but you desperately need to sneak some fixes.
So yes, you should have hot-fixes to standards just for those cases. One would state that the response of 302 for POST/PUT/DELETE should unconditionally trigger GET. And it should be in the spec years ago.
And no, you can't just "increment version number". Realistically you can't, pretending you can is silly too.
There is the same problem with laws: you first pass them, then you discover some flaws but no easy way to patch.
While this protection is a good idea, it doesn't change the fact that a redirect to a resource that is DELETEable would have an unexpected and unpleasant side-effect if the application developer was expecting the browser to issue a GET request.
Think about, e.g., a "delete this message and go to the next in your inbox" kind of functionality being implemented like this. Not that such an implementation would be the best idea, but it's a thought experiment.
So in some cases you could get a 404, or the endpoint treats everything as a GET request, or as you say the redirect URI actually has its own delete method that you assume won't be used after a redirect.
It seems easy to blame the browser, not least because it's also IE, but your code should take stuff like that into account, especially when dealing with destructive requests.
To be honest though, and this may be through ignorance on my part, I don't get why you'd issue a redirect on an AJAX request after performing a delete or whatever.
If I sent an AJAX request to delete a widget I wouldn't expect to get any data back, because I'm not asking for it. I'd want at least an empty 200 OK response for a successful delete or a relevant error code. And then I could react accordingly based on the result.
The design that allows IE9 to do this appears to just cut corners.
RFC 1945 and RFC 2068 specify that the client is not allowed
to change the method on the redirected request. However, most
existing user agent implementations treat 302 as if it were a 303
response, performing a GET on the Location field-value regardless
of the original request method. The status codes 303 and 307 have
been added for servers that wish to make unambiguously clear which
kind of reaction is expected of the client.